# -*- coding: iso-8859-15 -*-

#############################################################################
#
# file          : mkt.py
# author        : Wouter van Ooijen (wouter@voti.nl)
# function      : MicroKit application builder
#
# (c) Wouter van Ooijen 2009, 2010, 2011
#
# All rights reserved for this mkt.py file. 
#
# Running this file as a tool to create an embedded applications has
# no implication whatsoever for the legal status of that application.
# This "no consequences" statement explicitly covers all assmebler, 
# C or C++ code exported by or generated from this tool.
# This statement does *not* cover to the documentation of this tool.
# But do check the license(s) of the external C librarie(s) (that
# come with the compiler) that you (probably implicitly) use.
#
# V1.02
#    timing of kbd reading for HU board corrected
# V1.01
#    #define bool / operator<<( char ) erros corrected
#
#############################################################################

import sys, math, imp, os, re, subprocess, inspect, tempfile, shutil

def Import_Class( Old = None, Export = [] ):
   "Python has no in-file module concept, so I use this function "
   "to create a module from a class, and import all its content. "
   class dummy(): pass
   if type( Old ) == type( dummy ):
      New = imp.new_module( Old.__name__ )
      globals()[ Old.__name__ ] = New
      for Name in Old.__dict__.keys():
         New.__dict__[ Name ] = Old.__dict__[ Name ] 
         if ( Export == "*" ) or ( Name in Export ):
            globals()[ Name ] = Old.__dict__[ Name ] 
         # this is no longer allowed in Python >= 3.0:
         # del Old.__dict__[ Name ]
         sys.modules[ Old.__name__ ] = New
   else:
      for X in Old:
         Import_Class( X, Export )

class Global:
   "global stuff, does not fit anywhere else"

   Version   = "V1.03"
   Modified  = "2012-04-14"
   Name      = "mkt"

   ##########################################################################
   #
   #   Next is a list of things that could and/or should be done. 
   #   Some might actually get done before hell freezes over :)
   #
   ##########################################################################

   ToDoList  = """   
      max_minint will not << correctly??
      new pspad install does not claim .ppr?? cannot be made default??
      lpcflash  
      -run does a clear first :(      
      document #requires
      hyppoo edit? http://www.hippoedit.com/
      textpad? => file changed? find errors? // probleem
      notepad++?
      allow sections everywhere

      MCB2130 kitt werk niet :(
      idem olimex debug ook niet!
      fast IO - now twice defined? what if no fast IO yet it is configured?
         document,test speed
      redefining on the command line gives duplicate definitions
      stack allocations
      auto-generate command line interface documentation
      dev-cpp integratie
      include-probleem met Insight
      all-in-1 installer
      keypads
      exceptions
      debug with fonts

    document generator:      
       example files to file
       cross-references
       index
       title page / content
       rtf
       literal / code variations
       #ignore, both as section and as code?
       empty line before/after code (exchange code/pre removes only before)
       table captions, references      
      
   low priority:
      suppress warnings on 2nd compile
      check for duplicate file names
      pymedia: direct handling of mpeg!
      error handling - disable option!
      memory allocation
      graphics, t6963  
      integrate font functions
      section-problematiek...
      links to board's schematics
      board examples
      foto's for the hu armboard jumper settings
      default baudrate depends on xtal (also on cclk?)
      sort configuration items by name?
      how to accelerate C code by placing it in RAM?
      KS0108: flip cs polarity, flip x y, rotate, mirror
      print font area
      print font scrolling
      poked config values overwrite configuration string names, juk!
      font ook met beperkte charset
      werkt een .mkt file??
      article lpc21isp
      ARM link/bookmark
      implement memory allocation
      implement clock speed
      [no] select terminal
      auto-generate calling interface list
      clcd stride in bits (img converter mag dat anders doen...)
      1x16 LCD!
      http://en.wikipedia.org/wiki/X_BitMap
      http://en.wikipedia.org/wiki/Netpbm_format
      font-to-fontref, bmp-to-bitmap-color
      http://websitetips.com/fonts/pixel/
      http://www.iamcal.com/misc/fonts/
      generate C headers from documentation and test (or don't have
         plain C headers anyway)
      start OCD commander met de juiste interface - wiggler voor v2,v3, 
         openocd voor v4
      let op als een andere dan lpc21isp op de seriele poort staat!!
      zet vpb divisor
      LCD on hu-v2 does not always work?? == not with graophic LCD!!
      why can't ocd_commander close its process?
      UART alleen als er UARTs zijn, UART moet chip-specifiek!
      glcd auto_init
      size report: show source file name, export to cvs, -s<name>
      write range of IO pins faster
      run_ram_default etc
      reduce homepage, or include in this file? (include version in homepage!)
      could collapsing the documentation etc work with notepad++?
      can't have a #code inside a list?
      CLCD jump at 8, slowdown factor
      mt2106 page, mention power supply, JTAG pins
      mt2138 -> lpc2138
      mt2138 - no LCD when JTAG??
      pin connect > x on LPC2148
      compile should not mention the 'plain' filename but the source name?
      use a real system-defined temp directory?
      show elapsed time
      maak een mkt_lsp_write
      flash laden met insight werkt niet
      lpc21isp werkt niet met hogere COM poorten?
      overrulen op de command line geeft dubbele #defines
      show code & data sizes summary
      download generated .hex of .bin file without sources
      'require' new sources in a #configure
      mkt_cclck
      [no]list mag wat netter verwerkt worden in Python, gebruik pool van opties?
      compile from within UltraEdit gives strange \m warnings, 
        (when file with path) and can't kill deamons
      LCD-20 werkt niet
      errors from both list file and normal compilation
      PORT=COM1 for LPC21isp, default with new arm is com5 (needs 'free' check)
      ongeldig bord geeft nu als foutmeling 'geen chip gedefinieerd'
      foutmelding als deamon niet geopend kan worden!
         == not intalled, not connected...
      alignmen probleem bij Udo
      kill can take a lot of time :( (python version?)
      stdint??
      kill-deamons runt niet vanuit pspad (win32extensions not found)
      'external' board definitions?
      beep.c from RAM works when single-stepping, but NOT when run
         idem kitt.c, from ROM runs OK (stopped at 0x10)
         breakpoint-@stack-set-continue: no problem
         *en daarna ook niet meer*
         moet nu ook resetten na usb-connect-disconnect (klopt?)
      check snelheid (klokje?) klopt nu niet
      LCD code is een zootje
      probleem met #define voor soort LCD
      xtal is blijkbaar nog niet verplicht - niets is nog verplicht?
      make executable from python code? no need for tcl/tk...
      generate text at linker kantlijn
      python anchors werken niet goed in python 3.01?
      check configuration
      gebruik bij eval van de configs een dict met de andere configs
         act on it...
      python anchor is slooooow, en PSPad lust de // of \\ niet
      check stack init
      check clock init
      check compile c++
      C++ static inits
      flash-based RAM downloader?
      'default fatal error handler' text ends up in the header
      -ansi? geeft veel errors...
      -O3? specify optimization some other way?
      separate sections??
      list texts of error messages?
      /* C */ for C++
      notice should be used in all generated files
           KEYPAD
      format assembler call headers : needed spaces only!
      add #toc as document class instead of automatic, next level headers?
      aapcs link
      list of MK_ fatal errors, auto-generate?
      fast/slow IO ook in config
      busy waiting => mention linker (run-from-ram) and config (clocks)
      .mkx headers section needs more explanation __assemblker__ etc, 
      ook #configure, kan header: #define ook?
      one breakpoint or two breakpoints?
      wat gebrurt er als je DevCpp save'd onder een andere project naam??
      all 'todo' markers
      fatal error codes
      "#section header:" examples, werkt het, "C", #ifdef assembler, etc
      RAM layout explanation (stack, heap, etc)
      reset-preserved variables: separate section
      kbd -> keypad, keyboard is for AT-style keyboards
      mkt_input enzo moeten ook ge-hernummerd worden?
      Ram loading: exclude RAM 120-1ff 
         (and top 288, but no real need to do that)
      HD44780 custom characters : test
      HD66717 display
      ogg-vobis-tremor lib
      allocate a peripheral (static?, dynamic?)
      UART use/clear fractional divider
      C++ initialisation
      (optional) access to IAP features (write a bootloader)
      Microchip MIPS
      Cortex M3
      optimal 'write 8 bits to consequtive GPIO pins'
      (optionally) support Philips RAM uploader (must exclude some RAM)
      UART zonder deel routine?
      sw pwm werkend, netter, ook andere sample rates
      user CCLK but no PCLK: define PCLK = CCLK
      gpio omschakelen naar fast (=> selecteerbaar!)
      mcb2130 verder integreren: lsp, potmeter, LPC2138
      armboard V1 met 2x16 LCD
      sommige write LED delays zijn niet nodig
      CPP LCD init niet altijd goed? (wel als ik debug...)
      waarom werkt DA out niet?
      cvs, versions as string?
      for USB the peripheral clock must be >= 18 MHz
      - #define MK_INTERUPT_N_TIMER0 4
      andere interrupts en timers
      FIQ
      andere manier van printen
      interrupt code needs a frame pointer?? other registers?
      integrate memmove etc. with my functions!
      why nos asm debug in insight?
      implement stack allocation
      implement stack checking
      implement stack fill
      implement 3 "set stack" subroutines : test
      chip header files (article)
      http://www.gnu-pascal.de/gpc/h-index.html
      array-pool memory allocation and deallocation
      doc text after "#end list" is lost??
      "article name" creates empty-named article..
      implement and document MK_HS_BOOT, MK_PORT, MK_BAUDRATE
      describe armboard V2, MCB2130
      toevoegen: LPC2138 bord, ADuC7020      
      import_class does not rebind class-refernces, 
         works only when everything is independent or made global
      http://www.boost.org/doc/libs/1_43_0/libs/mpl/doc/tutorial/dimensional-analysis.html  
      http://eden.rutgers.edu/~lauderda/ctutorial/yeesh.htm       
   """
   
   def Kill_Process( procname ):
      "Kills a processes by process name"
      ""
      "adapted from "
      "   C:\PythonXX\Lib\site-packages\win32\scripts\killProcName.py"
      "Uses the Performance Data Helper to locate the PIDs, then kills it."
      "This is very slow on the Oudenoord PC's, maybe because of the"
      "older Python (2.4 IIRC)"
      
      import win32api, win32pdhutil, win32con, sys
   
      # Change suggested by Dan Knierim, who found that this performed a
      # "refresh", allowing us to kill processes created since this was run
      # for the first time.
      try:
         win32pdhutil.GetPerformanceAttributes('Process','ID Process',procname)
      except:
         pass
    
      pids = win32pdhutil.FindPerformanceAttributesByName( procname )
    
      # If _my_ pid in there, remove it!
      try:
         pids.remove( win32api.GetCurrentProcessId())
      except ValueError:
         pass
    
      for pid in pids:
         handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0,pid)
         win32api.TerminateProcess(handle,0)
         win32api.CloseHandle(handle)
   
   def Try_Kill_Process( Name, Message = None ):
      try:
         Kill_Process( Name )
         return 1
      except:
         if Message != None:
            print( Message )
         return 0
      
   ##########################################################################
   #
   # global constants
   #
   # these are imported into the global namespace
   #
   ##########################################################################

   Kb        = 1024
   Mb        = Kb * Kb
   kHz       = 1000
   MHz       = kHz * kHz

   
   Define_Globals = """
      // multiplication factors
      #define Kb  1024
      #define Mb  ( Kb * Kb )
      #define kHz 1000
      #define MHz ( 1000 * 1000 )
   """
   
   Known_Sections = [ "configuration", "c", "cpp", "c++", "asm" ]      

   ##########################################################################
   #
   # copyright notice for generated files
   #
   ##########################################################################
   
   Notice = """
      This file is generated by %s %s (%s)
      
      (c) 2009 Wouter van Ooijen (wouter@voti.nl)
      
      Using this file with the mkt (MikroKit) application builder 
      is allowed, without any consequences for the application 
      (whether executable, binary, or hex image) being built.
      """ % ( Name, Version, Modified )

   def Pause( Msg = "press retrn to continue" ):
      try:
         # pre Python 3.0
         Dummy = raw_input( Msg )
      except:
         # Python 3.0 and later
         Dummy = input( Msg )
         
      # the list of floting point functions         
   floating_point_functions_list = """\
__addsf3|__adddf3|__addtf3|__addxf3|__subsf3|__subdf3|__subtf3|__subxf3|\
__mulsf3|__muldf3|__multf3|__mulxf3|__divsf3|__divdf3|__divtf3|\
__divxf3|__negsf2|__negdf2|__negtf2|__negxf2|__extendsfdf2|\
__extendsftf2|__extendsfxf2|__extenddftf2|__extenddfxf2|__truncxfdf2|\
__trunctfdf2|__truncxfsf2|__trunctfsf2|__truncdfsf2|__fixsfsi|__fixdfsi|\
__fixtfsi|__fixsfdi|__fixdfdi|__fixtfdi|__fixxfdi|__fixsfti|__fixdfti|\
__fixtfti|__fixxfti|__fixunssfsi|__fixunsdfsi|__fixunstfsi|__fixunsxfsi|\
__fixunssfdi|__fixunsdfdi|__fixunstfdi|__fixunsxfdi|__fixunssfti|\
__fixunsdfti|__fixunstfti|__fixunsxfti|__sisf|__sidf|__sitf|__sixf|__disf|\
__didf|__ditf|__dixf|__tisf|__tidf|__titf|__tixf|__unsisf|__unsidf|__unsitf|\
__unsixf|__undisf|__undidf|__unditf|__undixf|__untisf|__untidf|__untitf|\
__untixf|__cmpsf2|__cmpdf2|__cmptf2|__unordsf2|__unorddf2|__unordtf2|\
__eqsf2|__eqdf2|__eqtf2|__nesf2|__nedf2|__netf2|__gesf2|__gedf2|__getf2|\
__ltsf2|__ltdf2|__lttf2|__lesf2|__ledf2|__letf2|__gtsf2|__gtdf2|__gttf2|\
__powisf2|__powidf2|__powitf2|__powixf2|complex__mulsc3|complex__muldc3|\
complex__multc3|complex__mulxc3|complex__divsc3|complex__divdc3|
complex__divtc3|complex__divxc3"""         
                    
class Junk:
   ##########################################################################
   #
   # mkt file names
   #
   ##########################################################################
   
   Mkt_Header_H     = "_mkt__header.h"       # included by user files
   Mkt_Config_H     = "_mkt__config.h"       # generated configuration file
   Mkt_Config_TXT   = "_mkt__config.txt"     # for debugging only
   Mkt_Lib_H        = "_mkt__h_lib.h"        # mkt library header
   Mkt_Lib_ASM      = "_mkt__s_lib.s"        # mkt library asm source
   Mkt_Lib_C        = "_mkt__c_lib.c"        # mkt library C source
   Mkt_Lib_CPP      = "_mkt__cpp_lib.cpp"    # mkt library C++ source
   Mkt_Link_Script  = "_mkt__linkscript"     # linker script
   Mkt_Insight_Cmd  = "_mkt__insight_cmd"    # Insight startup cmd script
   Mkt_OOCD_Cfg     = "openocd.cfg"          # OpenOCD configuration
   Mkt_Temp         = r"c:\temp\_mkt_temp"   # dir for temprary files
   # Mkt_Temp         = r"C:\_mkt_temp"   
   # Mkt_Temp         = r"D:\_mkt_temp"   
   
   # does mot work:
   # Mkt_Temp         = tempfile.gettempdir()
   
   
   ##########################################################################
   #
   # Configuration item names and (fixed) values
   #
   ##########################################################################
   
   Mkt_Prefix           = "mkt_"
   Mkt_GCC              = "GCC"
   Mkt_Chip             = "chip"
   Mkt_Xtal             = "xtal"
   
   Mkt_Memory           = "memory"
   Mkt_ROM              = "rom"
   Mkt_RAM              = "ram"
   
   Mkt_Run              = "run"
   Mkt_Insight          = "insight"
   Mkt_Lpc21isp         = "lpc21isp"
   Mkt_Ocd_Commander    = "ocd_commander"
   
   Mkt_Link             = "link"
   Mkt_Simulator        = "sim"
   Mkt_Wiggler          = "wiggler"
   Mkt_FTDI2232         = "ftdi2232"
   Mkt_ARM_USB_OCD      = "arm_usb_ocd"
   
   Mkt_Port             = "port"
   Mkt_Baudrate         = "baudrate"
   Mkt_Error_Handling   = "error_handling"
   Mkt_Default_Baudrate = "19200"
   Mkt_Serial_Baudrate  = "19200"
   Mkt_FTDI_Baudrate    = "38400"
   Mkt_Serial_Port      = "COM1"
   Mkt_FTDI_Port        = "COM4"
   
   Mkt_LED_Template     = "led_%s_pin"
   Mkt_LEDs_N           = "leds_n"
   Mkt_LEDs_595_HQ      = "leds_595_hq"
   Mkt_LEDs_595_SQ      = "leds_595_sq"
   Mkt_LEDs_595_D       = "leds_595_d"
   
   mkt_keypad_type      = "keypad_type" 
   Mkt_Keypad_HUV4      = "keypad_hu_v4"
   
   mkt_clcd_Type        = "clcd_type"
   mkt_clcd_Lines       = "clcd_lines"
   mkt_clcd_Columns     = "clcd_columns"
   mkt_clcd_Jump        = "clcd_jump"
   mkt_clcd_E           = "clcd_e"
   mkt_clcd_RW          = "clcd_rw"
   mkt_clcd_RS          = "clcd_rs"
   mkt_clcd_D4          = "clcd_d4"
   mkt_clcd_D5          = "clcd_d5"
   mkt_clcd_D6          = "clcd_d6"
   mkt_clcd_D7          = "clcd_d7"
   
   mkt_glcd_type        = "glcd_type"
   mkt_glcd_h           = "glcd_h"
   mkt_glcd_v           = "glcd_v"
   mkt_glcd_cs1         = "glcd_cs1"
   mkt_glcd_cs2         = "glcd_cs2"
   mkt_glcd_rw          = "glcd_rw"
   mkt_glcd_di          = "glcd_di"
   mkt_glcd_e           = "glcd_e"
   mkt_glcd_d0          = "glcd_d0"
   mkt_glcd_d1          = "glcd_d1"
   mkt_glcd_d2          = "glcd_d2"
   mkt_glcd_d3          = "glcd_d3"
   mkt_glcd_d4          = "glcd_d4"
   mkt_glcd_d5          = "glcd_d5"
   mkt_glcd_d6          = "glcd_d6"
   mkt_glcd_d7          = "glcd_d7"
   
   Mkt_Board            = "board"
   Mkt_HU_V2            = "hu_arm_v2"
   Mkt_HU_V3            = "hu_arm_v3"
   Mkt_HU_V4            = "hu_arm_v4"
   Mkt_P2148            = "olimex_p2148"
   Mkt_MT_2106          = "olimex_mt_2106"
   Mkt_MT_2138          = "olimex_mt_2138"
   Mkt_MCB2130          = "keil_mcb2130"
   Mkt_MC32USBST        = "microchip_pic32_usb_starterkit"
   Mkt_NDSi             = "ndsi"
   Mkt_Emulator         = "emulator"
   Mkt_Ideas            = "ideas"
   Mkt_NoGBA            = "nogba"
   Mkt_DeSmuME          = "desmume"
   Mkt_dualis           = "dualis"
   
   List_Of_Boards = [ 
      Mkt_HU_V2, 
      Mkt_HU_V3, 
      Mkt_HU_V4,  
      Mkt_P2148, 
      Mkt_MT_2106,
      Mkt_MT_2138,
      Mkt_MCB2130, 
      Mkt_MC32USBST,
      Mkt_NDSi,
   ] 
   
   List_Of_NDS_Emulators = [
      Mkt_Ideas,
      Mkt_NoGBA,
      Mkt_DeSmuME,
      Mkt_dualis,
   ]

class Tests:
   "When called with a string, a test function returns whether the string "
   "passes the test. When called with None, the function returns a very "
   "short string that describes the what the string should be. "
   ""
   "NOTE: this class is used as a module"
 
   def Is_Anything( X ):
      "dummy pass-all test"
      if X == None:
         return "anything"
      return 1      
   
   def Is_String( X ):
      "another pass-all test, but the argument is supposed to be a sring"
      if X == None:
         return "any string"
      return 1      
      
   def Is_Numeric( X ):
      "test whether the argument can be evaluated to a numerical value"   
      if X == None:
         return "numeric"
      try: 
         N = 15 + eval( X )
         return 1
      except:    
         return 0 
         
   def Is_Boolean( X ):
      "test whether the argument can be evaluated to a boolean value"
      if X == None:
         return "boolean (0 or 1)"
      try: 
         N = 15 + eval( X )
         if ( N == 15 ) or ( N == 16 ):
            return 1
      except:    
         return 0 
          
class Files:
   "some file and file-name related functions"
   
   def File_DoubleSlash( Name ):
      "replace all single \ with \\ "
      X = Name.replace( "\\\\", "*" ) \
         .replace( r"\\", r"\\\\" ) \
         .replace( "*", r"\\\\" )
      # print "double:", Name, X   
      return X      
   
   def File_Extension( File_Name ):
      "return the file extension of File_Name (without the dot)"
      Dummy, Extension = os.path.splitext( File_Name )
      return Extension[ 1: ] if len( Extension ) > 0 else ""
   
   def File_Base( File_Name ):
      "return the base name of File_Name (without the dot+extension)"
      Base = os.path.basename( File_Name )
      return Base.replace( "." + File_Extension( Base ), "" )
      
   def Replace_Extension( Name, Extension ):
      "remove an existing extesion, add the specified one"
      Old_Extension = File_Extension( Name )
      if Old_Extension == "":
         return Name + "." + Extension
      else:
         return Name.replace( "." + Old_Extension, "." + Extension )   
         
   def File_Exists( Name ):
      "test if the file exists (== can be opened for reading)"
      try:
         F = open( Name, "r" )
         F.close()
         return 1
      except:
         return 0 
         
   def Clever_File_Find( File_Name, Suffixes ): 
      "if the File_Name itself exists, return it."
      "if not, try the specified suffixes,"
      "if exactly one is found, return that one."     
      if File_Exists( File_Name ):
         return File_Name
      N = 0
      for Suffix in Suffixes:
         if File_Exists( File_Name + Suffix ):
            N += 1
            Suffix_Name = File_Name + Suffix
      if N == 1:
         return Suffix_Name
      return File_Name
            
   def Directory_Files_Delete( Path ):    
      import os  
      if not os.path.isdir( Path ):
         return 
      for x in os.listdir( Path ):
         FullPath = os.path.join( Path, x )
         if os.path.isfile( FullPath ):
            try:
               os.remove( FullPath )
            except:   
               print( "*** could not remove [%s]" % FullPath )
               
   def File_Find_Executable(executable, path=None):
       """Try to find 'executable' in the directories listed in 'path' (a
       string listing directories separated by 'os.pathsep'; defaults to
       os.environ['PATH']).  Returns the complete filename or None if not
       found
       """
       if path is None:
           path = os.environ['PATH']
       paths = path.split(os.pathsep)
       #print paths
       extlist = ['']
       pathext = os.environ['PATHEXT'].lower().split(os.pathsep)
       (base, ext) = os.path.splitext(executable)
       if ext.lower() not in pathext:
          extlist = pathext
       #print executable
       #print extlist            
       for ext in extlist:
           execname = executable + ext
           if os.path.isfile(execname):
               return execname
           else:
               for p in paths:
                   f = os.path.join(p, execname)
                   #print f
                   if os.path.isfile(f):
                       return f
       else:
           return None   
           
   def File_Open( File_Name, Mode, Location = None ):
      "open the file, create required subdirectories, "
      "raise a user error if not possible"
   
      File_Name = os.path.normpath( File_Name )
   
      try:
         os.makedirs( os.path.dirname( File_Name ))
      except:
         pass
   
      try:
         File = open( File_Name, Mode )         
         return File
      except:
         Errors.Raise( "can not open file '%s'" % File_Name, Location )
          
   def Split_Link( X, Url = 0 ):
      R1 = ""
      R2 = ""
      for c in X:
         if (
            ( c in ",)(!.:" )
            and (( not Url ) or R1 + c == X )
         ):
            R2 += c
         elif R2 != '':
            R2 += c
         else:
            R1 += c    
      return ( R1, R2 ) 
      
   def MakeDir( Path ):
      try: 
         os.makedirs( Path ) 
      except: 
         pass   
             
class Errors:
   "Error handling"
   ""
   "NOTE: this class is used as a module"
   
   Config_Error_Prefix = "configuration error: "
   
   class _Error_Base( IOError ):
      def __init__( self, Message, Location ):
         self.Message = Message
         self.Location = Location
   
      def __str__( self ):
         Text = self.Message
         if self.Location != None:
            Text = str( self.Location ) + ": " + Text
         return Text
   
   class _Error( _Error_Base ):
      def __init__( self, Message, Location ):
         Errors._Error_Base.__init__( self, Message, Location )
   
   class _Panic( _Error_Base ):
      def __init__( self, Message, Location ):
         Errors._Error_Base.__init__( self, Message, Location )
   
   def Raise( Message, Location = None ):
      "raise a user error"
      raise Errors._Error( Message, Location )
      
   def Panic( Message, Location = None ):  
      "raise an internal error" 
      raise Errors._Panic( Message, Location )
   
   def Warning( Message, Location = None ): 
      "not a real error, just print in error format"  
      W = Errors._Error( Message, Location )
      print( str( W ))
      
class Location:
   "Abstracts the location of a source line: source file name, line number. "
   "Used for user error handling and generation of #line references"

   def __init__( self, File = None, Line = None ):
      self.File = File
      self.Line = Line

   def Anchor( self ): 
      'returns the #line 12,"file.c" formatted line,'
      'for use in .c files to force the location of error messages.'
      return '#line %d "%s"\n' % ( self.Line, File_DoubleSlash( self.File ))

   def __str__( self ):
      "return the location in a format that resembles a gcc error message"   
      if self.File == None:
         return ""
      elif self.Line == None:
         return "[%s]" % self.File
      else:
         return "%s:%d" % ( self.File, self.Line )
         
   def Text( self, Prefix = "", Suffix = "", Default = "" ):
      "idem, but" 
      "- add the Prefix if a location is present"
      "- return Default if not"
      Txt = str( self )
      if Txt != "":
         Txt = Prefix + Txt + Suffix
      else:
         Txt = Default   
      return Txt

class Transform:
   "some transformations on strings, mostly intended for source text"
   ""
   "NOTE: this class is used as a module"

   def Unchanged( X ):
      return X
      
   def RPad( S, N, Filler = " " ):
      "retrun S, right-padded with Filler's to length N"
      while len( S ) < N:
         S += Filler
      return S
   
   def Hex8( N ):
      "return N as 8-digit hexadecimal number (with leading 0's)"
      X = hex( N ).replace( 'L', '' ).replace( '0x', '' )
      while len( X ) < 8:
         X = '0' + X
      return '0x' + X 
      
   def Comment( S = "", Left = "/*", Right = "*/", Fill = " " ):
      "return S embedded in a right-side-padded enclosed comment"
      return (
         Left + 
         Fill + 
         RPad( S, 78 - ( 1 + len( Left + Right )), Fill ) + 
         Right )
      
   def Include_Local( File ):
      'return the source line for #include "file"'
      return "#include " + '"' + File.replace( "\\", "\\\\" ) + '"'
       
   def Include_Lib( File ):
      "return the source line for #include <file>"
      return "#include " + '<' + File + '>'
      
   def Evaluate( S, Default = None ):
      "evaluate S, retrun Default on failure"
      try:
         return eval( S )
      except:
         return Default
         
   _Unique_List = []
   _Error_List  = []   
   _Unique = 1   
   
   def Unique( S ):
      "replace each occurrence of #UNIQUE and #ERROR by a unique number"
      global _Unique, _Unique_list, _Error_List
      
      if S.find( "\n" ) != -1:
         X = ""
         for Line in S.split( "\n" ):
            if X != "":
               X = X + "\n"
            X = X + Unique( Line ) 
         return X   
      
      R = S.replace( "#UNIQUE_ERROR", str( _Unique ), 1)
      if R != S:
         # print( "*** %3d [%s]" % ( _Unique, S ))
         _Error_List.append(( _Unique, R ))
         _Unique += 1
         return Unique( R )
         
      R = S.replace( "#UNIQUE", str( _Unique ), 1)
      if R != S:
         _Unique_List.append(( _Unique, R ))
         _Unique += 1
         return Unique( R )
      
      return S
            
   def Indent( Lines, Prefix, N ):
      for Dummy in range( 0, N ):
         Prefix = " " + Prefix
      Result = ""
      for Line in Lines.split( "\n" )[ :-1]:
         Result += Prefix + Line + "\n"
      return Result 
      
   def Indent_Count( Line ):
      N = 0
      while ( Line + "*" )[ N ] == " ":
         N = N + 1
      return N
               
class Text:
   "handling of text, mainly for asm/C/C++ source"
   ""
   "NOTE: this class is used as a module"
   
   def Initial_Whitespace( X ):
      if X[ 0 ] != "\n":
         return ""
      ws = ""
      # print "[" + X + "]"
      while len( X ) > 1 + len( ws ) and X[ 1 + len( ws ) ] == " ":
         ws += " "
         # print len( X ), len( ws ), len( X ) > len( ws )
         # print X[ 1 + len( ws ) ]
      # print ws, X   
      return ws

   class One_Line:
      "abstraction for a single line read from a file"
   
      def __init__( self, Text, Loc = None ):
         if Loc == None:
            self.Location = Location()
         else:
            self.Location = Loc
         self.Text = Text 
   
      def Anchor( self ):
         if self.Location == None:
            Errors.Panic( "Anchor requested for line without Location '%s'" 
               % self.Text )
         return self.Location.Anchor()
         
      def Nr_And_Text( self ):
         if self.Location == None:
            Loc = "[     ]"
         else:
            Loc = "[%05d]" % self.Location.Line
         return "%s:%s" % ( Loc, self.Text )
         
      def Nr( self ):
         if self.Location == None:
            rerurn -1
         else:
            return self.Location.Line            
         
      # return the #line line for 'misleading' the compiler
      def __str__( self ):
         return "%s '%s'" % ( 
            str( self.Location.Text( Default = "[]" )), 
            self.Text.replace( "\\", "\\\\" ) )
         
   class Lines:
      "bunch of lines, can be read from a file, or to be written to one"
      
      def Unchanged( x ):
         return x
   
      def __init__( 
         self, 
         File_Name = None, 
         Write_Name = None, 
         Filter = Unchanged 
      ):        
         self.Name = File_Name
         self.Lines = []
         self.Nr = 0
         if File_Name != None:
            self.Extension = File_Extension( File_Name ).lower()
            File = File_Open( File_Name, "rU" )
            for Line in File.readlines():
               self.Add( Filter( Line ))
            File.close()
         if Write_Name != None:
            self.File_Name = Write_Name
            
      def Set_File_Name( self, File_Name = None ):
         if File_Name != None:
            self.File_Name = File_Name
            
      def Add( 
         self, 
         Lines, 
         Arg_Location = None, 
         Chop = None,
         Filter = Unchanged 
      ):
         self.Nr = self.Nr + 1
         if Lines.endswith( "\n" ):
            Lines = Lines[ :-1 ]
         for Line in Lines.split( "\n" ):
            if Arg_Location == None:
               Loc = Location( self.Name, self.Nr )
            else:
               Loc = Arg_Location
            if Chop != None:
               if Line.startswith( Chop ):
                  Line = Line.replace( Chop, "", 1 )
            self.Lines.append( One_Line( Filter( Line ), Loc ))
            
      def Add_Line( self, Line ):
         self.Add( Line.Text, Arg_Location = Line.Location )
         
      def Add_Lines( self, Lines ):
         for Line in Lines.Lines:
            self.Add_Line( Line )
         
      def Write( 
         self, 
         File_Name = None, 
         Filter = Unchanged 
      ):
         if File_Name == None:
            File_Name = self.File_Name
         File = File_Open( File_Name, "w" )
         # print( File_Name )
         for Line in self.Lines:
            # print( Line.Text )
            File.write( Filter( Line.Text ))
            File.write( "\n" )
         File.close()
         
      def Print( self, Prefix = "" ):
         for Line in self.Lines:
            print( Prefix + Line.Text.replace( "\n", "" ))
   
      def Text_Only( self ):
         Result = []
         for Line in self.Lines:
            Result.append( Line.Text )
         return Result
            
      def Number_Of_Lines( self ):
         return self.Nr
         
      def __str__( self ):
         Result = ""
         for Line in self.Lines:
            Result += str( Line ) + "\n"
         return Result            
   
      def Plain_Text( self, Prefix = "" ):
         Result = ""
         for Line in self.Lines:
            Result += Prefix + Line.Text + "\n"
         return Result            
         
      def __add__( self, Other ):
         Result = Lines()
         Result.Add_Lines( self )
         Result.Add_Lines( Other )
         return Result
   
   class Lines_From_Text( Lines ):
      def __init__( self, Text, File_Name = None ):
         Lines.__init__( self )
         self.Add( Text, Chop = Initial_Whitespace( Text ))
         self.Set_File_Name( File_Name )
         
   def Lines_From_Lines( Bulk ):
      Result = Lines()
      for Line in Bulk:
         Result.Add_Line( Line )
      return Result
         
   # convert to DOS file format (just read and write back)      
   def Convert_To_DOS( Name ):      
      # print( "convert [%s]" % Name )
      Lines( Name ).Write( Name )      
       
class Memory: 
   "memory regions"  

   class Memory_Region:
      def __init__( self, Name, Start, Size ):
         self.Name = Name
         self.Start = Start
         self.Size = Size
         self.Reserved = 0
         
      def __str__( self ):
         return (
            "   " + RPad( self.Name, 10 ) + ": " +
            "ORIGIN = " + Hex8( self.Start + self.Reserved ) + ", " +
            "LENGTH = " + Hex8( self.Size - self.Reserved ))         
   
   class RAM( Memory_Region ):
      def __init__( self, Start = 0, Size = 0 ):
         Memory_Region.__init__( self, "ram", Start, Size )
   
   class ROM( Memory_Region ):
      def __init__( self, Start = 0, Size = 0 ):
         Memory_Region.__init__( self, "rom", Start, Size )
   
   class VEC( Memory_Region ):
      def __init__( self, Start = 0, Size = 0 ):
         Memory_Region.__init__( self, "vec", Start, Size ) 
         
Import_Class( Global, Export = [ "Kb", "Mb", "kHz", "MHz" ])    
Import_Class( [ Errors ] )
Import_Class( [ Transform, Files, Junk, Tests, Text, Memory ], Export = "*" )
     
class Rule_Class:
   def __init__( self, Name, Check = None, Values = None ):
      self.Name = Name
      self.Check = Check
      self.Values = Values
      
   def Values_String( self ):
      X = ""
      Separator = ""
      for Value in self.Values:
         X = X + Separator + Value
         Separator = ", "
      return X         
      
   def __str__( self ):
      X = ""
      if self.Values != None:
         X = self.Values_String()
      return "rule %s [%s]" % ( self.Name, X )
      
   def Validate( self, Item ):
      if self.Values != None:
         self.Validate_List( Item )
      elif self.Check != None:
         self.Check( Item )
      else:
         Errors.Panic( "configuration rule %s has no check" % Rule.Name ) 
      
   def Validate_List( self, Item ):
      for Value in self.Values:
         if Value == Item.Value:
            return
      Errors.Raise( 
         ( Errors.Config_Error_Prefix
            + "configuration item '%s' has unknow "
            +  "value '%s'; allowed values are: %s." 
         ) % ( 
            Item.Name, 
            Item.Value, 
            self.Values_String()
         ))
            
   def Validate_Check( self, Item, Rule ):
      if not self.Check( Item.Value ):
         Raise( 
            ( Errors.Config_Error_Prefix
               + "configuration item '%s' has illegal "
               +  "value '%s'; it must be %s." 
            ) % ( Item.Name, Item.Value, self.Check( None )))
            
   def Header( self ):
      Result = Lines()            
      if self.Values != None:
         for Value in self.Values:
            Result.Add( Unique( 
               "#define %-20s #UNIQUE" % ( Mkt_Prefix + Value )))
      return Result
      
   def Export( self ):
      if self.Values != None:
         for Value in self.Values:
            globals()[ Mkt_Prefix + Value ] = \
               ( "%s" % ( Mkt_Prefix + Value ))
            if 0: print( "export %s" % ( Mkt_Prefix + Value ))
               
class Define:
   def __init__( self, Name, Value, Loc ):
      self.Name = Name
      self.Value = Value
      if Loc == None:
         self.Location = Location()
      else:
         self.Location = Loc
         
   def Matches( self, Value ):
      return self.Value.lower() == Value.lower()
      
class Configuration:
   "Storage pool for configuration items"

   def __init__( self, Text = Lines() ):
      self.Defines = []
      self.Rules = []
      for Line in Text.Lines:
         self.Parse( Line )

   def Get( self, Name, Default = None ):
      Name = Name.lower()
      Default_Name = self.Default_Name( Name )
      for Def in self.Defines:
         if Def.Name == Name:
            return Def
         if Def.Name == Default_Name:
            Default = Def   
      #if Default != None:
      #   self.Set( Default.Name, Default.Value, Default.Location, 1 )
      return Default
      
   def Get_Value( self, Name, Default = None ):
      Result = self.Get( Name, None )
      if Result == None:
         return Default
      return Result.Value      
      
   def Matches( self, Name, Value ):
      Result = self.Get( Name, None )
      if Result == None:
         return 0
      #print( Result.Value.lower() )
      #print( "++" + Value )
      return Result.Value.lower() == Value.lower()
           
   def Must_Get( self, Name ):
      Def = self.Get( Name, None )
      if Def == None:
         Errors.Raise( 
            Errors.Config_Error_Prefix + 
            "no configuration of '%s' found" % Name )
      return Def
         
   def Write( self, File_Name ):
      F = Lines()
      for Def in self.Defines:
         try:
            Value = str( 0 + eval( Def.Value ))
         except:
            Value = Mkt_Prefix + Def.Value
         F.Add( "#define %s %s" % ( Mkt_Prefix + Def.Name, Value ))
      F.Write( File_Name )   
      
   def Set( self, Name, Value, Location = None, Overwrite = 1 ):
      # print( "set '%s' '%s'" % ( Name, Value ) )
      Old = self.Get( Name, None )
      if Old != None:
         if Overwrite:
            Old.Value = Value
         else:   
            Text1 = Errors.Config_Error_Prefix + "redefinition of '%s'" % ( Name )
            Text2 = Old.Location.Text( 
               Prefix = "\n   ", Suffix = ": earlier definition")
            Errors.Raise( Text1 + Text2, Location )
      self.Defines.append( Define( Name.lower(), Value, Location ))
      
   def Default_Name( self, Name ):
      return Name + "_default"   
      
   def Set_Default( self, Name, Value, Loaction = None ):
      self.Set( self.Default_Name( Name ), Value, Location, 1 )
      
   def Add( self, Line, Text ):
      Name = Text.split()
      if len( Name ) < 1:
         Errors.Raise( 
            Errors.Config_Error_Prefix + "no item name",
            Line.Location )
      Name = Name[ 0 ] 
      Value = Text.replace( "#configure", "" ).replace( Name, "" ).strip()
      self.Set( Name, Value, Line.Location )
      
   def Add_Defines( self, Defines ):
      for Def in Defines:
         Name,Value = Def.split( "=" )[:2]
         self.Set( Name, Value, Overwrite = 1 )
            
   def Parse( self, Line ):
      # print( Line )
      Text = Line.Text.strip()
      if Text.startswith( r"//" ):
         pass
      elif Text.startswith( "#line" ):
         pass
      elif Text.startswith( "#define" ):
         self.Add( Line, Text.replace( "#define", "" ))
      elif Text.startswith( "#configure" ):
         self.Add( Line, Text.replace( "#configure", "" ))

   def __str__( self ):
      Text = ""
      for Def in self.Defines:
         Text = Text + ( "%-20s %-20s = %-30s\n" % 
            (  Def.Location, Def.Name, Def.Value ))
      return Text
      
   def Chip_Name( self ):
      # print( self )
      return self.Must_Get( Mkt_Chip ).Value

   def Numeric_Value( self, Name ):
      Item = self.Must_Get( Name )
      if not Is_Numeric( Item.Value ):
         Errors.Raise( 
            ( Errors.Config_Error_Prefix
               + "configuration item '%s' has illegal "
               +  "value '%s'; it must be numeric." 
            ) % ( Item.Name, Item.Value))
      return 0 + eval( Item.Value )
         
   def unused_Prefix( self, Name ):
      if not Name.startswith( Mkt_Prefix ):
         return Mkt_Prefix + Name.lower()
      return Name
         
   def Rule_Get( self, Name ):
      Name = Name.replace( "_default", "" ).lower()
      for Rule in self.Rules:
         if Name == Rule.Name:
            return Rule
      return None
      
   def Rule_Check( self, Name, Check ):
      Rule = Rule_Class( Name, Check = Check )   
      self.Rules.append( Rule )
      
   def Rule_Get_Or_Insert( self, Name ):
      Name = Name.lower()
      for Rule in self.Rules:
         if Name == Rule.Name:
            return Rule
      Rule = Rule_Class( Name, Values= [] )      
      self.Rules.append( Rule )
      return Rule
         
   def Rule_Extend( self, Name, Values ):
      Rule = self.Rule_Get_Or_Insert( Name )
      for Value in Values:
         Rule.Values.append( Value.lower())      
      
   def Check_Item( self, Item ):
      for Rule in self.Rules:
         if Item.Name == Rule.Name:
            Rule.Validate( Item )
            return
      Errors.Raise( 
         Errors.Config_Error_Prefix + 
         "unrecognised configuration item %s found" 
   % Item.Name.replace( Mkt_Prefix, "" ))      
      
   def Check( self ):
      #print( "config:" ); print( self )
      #print( "rules:" ); print( self.Rules )
      for Item in self.Defines:
         if not Item.Name.endswith( "_default" ) :
            self.Check_Item( Item )
         
   def External_Value( self, Item ):
      Rule = self.Rule_Get( Item.Name )
      if Rule == None:
         if 0:
            print( "configuration item '%s' has no rule" % Item.Name )
            return Item.Value
         else:
            Errors.Panic( "configuration item '%s' has no rule" % Item.Name )
      if Rule.Values == None:
         if Rule.Check == Is_String:
            return '"' + Item.Value + '"'
         else:
            return Item.Value
      else:
         return Mkt_Prefix + Item.Value
         
   def Extrapolate( self, Template, Start, End = 0 ):
      for N in range( Start, End, -1 ):    
         P = self.Get( Template % N, None )
         if P != None:
            Existing = self.Get( 
               Template % ( N - 1 ), 
               None  )
            if Existing == None:
               self.Set_Default( 
                  Template % ( N - 1 ), 
                  str( int( P.Value ) - 1 ))         
      
   def Header( self ):
      Result0 = Lines_From_Text( "\n//literal values for configuration items" )
      Result1 = Lines_From_Text( "\n//configured values of configuration items" )
      for Item in self.Defines:
         # print( Item.Name )
         if Item.Name.endswith( "_default" ):
            Without = Item.Name.replace( "_default", "" )
            if Item == self.Get( Without, None ):
               Result1.Add( "#define %-20s %s" % ( 
                  Mkt_Prefix + Without, 
                  self.External_Value( Item )))
         else:
            Result1.Add( "#define %-20s %s" %( 
               Mkt_Prefix + Item.Name, 
               self.External_Value( Item )))
      for Rule in self.Rules:         
         Result0 = Result0 + Rule.Header()
      return (
         Lines_From_Text( """
         """ )
         + Lines_From_Text( Global.Define_Globals ) 
         + Result0 
         + Result1
         + Lines_From_Text( """
         """ )
      )         
           
   def Export( self ):
      if 0: print( "export to Python globals" )
      for Item in self.Defines:
         if Item.Name.endswith( "_default" ):
            Without = Item.Name.replace( "_default", "" )
            if Item == self.Get( Without, None ):
               globals()[ Mkt_Prefix + Without ] = self.External_Value( Item )
               if 0: print( "export %s=%s" % 
                  ( Mkt_Prefix + Without, self.External_Value( Item ) ))
         else:
            globals()[ Mkt_Prefix + Item.Name ] = self.External_Value( Item ) 
            if 0: print( "export %s=%s" % 
               ( Mkt_Prefix + Item.Name, self.External_Value( Item ) ))
      for Rule in self.Rules:
         Rule.Export()
         if not ( Mkt_Prefix + Rule.Name ) in globals():
            globals()[ Mkt_Prefix + Rule.Name ] = None
      
   def Board_HU_LEDs( self, HQ, SQ, D  ):
      self.Set_Default( Mkt_LEDs_N,       "8" )
      self.Set_Default( Mkt_LEDs_595_HQ,  str( HQ ))
      self.Set_Default( Mkt_LEDs_595_SQ,  str( SQ ))
      self.Set_Default( Mkt_LEDs_595_D,   str( D ))
      
   def HD44780( self, Lines, Columns, RS, RW, E, D7 ):
      self.Set_Default( mkt_clcd_Type,     "hd47780" )
      self.Set_Default( mkt_clcd_Lines,    str(  Lines ))
      self.Set_Default( mkt_clcd_Columns,  str( Columns ))
      self.Set_Default( mkt_clcd_RS,       str( RS ))
      if RW != None:
         self.Set_Default( mkt_clcd_RW, str( RW ))
      self.Set_Default( mkt_clcd_E,        str( E ))
      self.Set_Default( "clcd_d7",         str( D7 - 0 ))
            
   def Board_Defaults( self ):
      Board = self.Get( Mkt_Board )         
      if Board == None:
         return
      # print( "board = [%s]" % Board.Value )
      if Board.Matches( Mkt_HU_V2 ):
         self.Set_Default( Mkt_Chip,      "lpc2106" )
         self.Set_Default( Mkt_Xtal,      "10 * MHz" )
         self.Set_Default( "cclk",        "60 * MHz" )
         self.Set_Default( Mkt_Link,      Mkt_Wiggler )
         self.Set_Default( Mkt_Baudrate,  Mkt_Serial_Baudrate )
         self.HD44780( 1, 16, 14, None, 13, 12 )
         self.Board_HU_LEDs( 2, 4, 6 )
      if Board.Matches( Mkt_HU_V3 ):
         self.Set_Default( Mkt_Chip,      "lpc2148" )
         self.Set_Default( Mkt_Xtal,      "12 * MHz" )
         self.Set_Default( "cclk",        "60 * MHz" )
         self.Set_Default( Mkt_Link,      Mkt_Wiggler )
         self.Set_Default( Mkt_Port,      Mkt_Serial_Port )        
         self.Set_Default( Mkt_Baudrate,  Mkt_Serial_Baudrate )
         self.HD44780( 1, 16, 14, None, 13, 12 )
         self.Board_HU_LEDs( 16, 4, 6 )
      if Board.Matches( Mkt_HU_V4 ):
         self.Set_Default( Mkt_Chip,      "lpc2148" )
         self.Set_Default( Mkt_Xtal,      "12 * MHz" )
         self.Set_Default( "cclk",        "60 * MHz" )
         self.Set_Default( Mkt_Link,      Mkt_FTDI2232 )
         self.Set_Default( Mkt_Port,      Mkt_FTDI_Port )
         self.Set_Default( Mkt_Baudrate,  Mkt_FTDI_Baudrate )
         self.Set_Default( mkt_keypad_type, Mkt_Keypad_HUV4 )
         self.HD44780( 1, 16, 14, None, 13, 12 )
         self.Board_HU_LEDs( 16, 4, 6 )
      if Board.Matches( Mkt_P2148 ):
         self.Set_Default( Mkt_Chip,      "lpc2148" )
         self.Set_Default( Mkt_Xtal,      "12 * MHz" )
         self.Set_Default( "cclk",        "60 * MHz" )
         self.Set_Default( Mkt_Link,      Mkt_ARM_USB_OCD )
         self.Set_Default( Mkt_Port,      Mkt_FTDI_Port )
         self.Set_Default( Mkt_Baudrate,  Mkt_FTDI_Baudrate )
         self.Set_Default( Mkt_LED_Template % 1, "11" ) # LED == P0.11
      if Board.Matches( Mkt_MT_2106 ):
         self.Set_Default( Mkt_Chip,      "lpc2106" )
         self.Set_Default( Mkt_Xtal,      "14745600" )
         self.Set_Default( "cclk",        "58982400" )
         self.Set_Default( Mkt_Link,      Mkt_ARM_USB_OCD )
         self.Set_Default( Mkt_Port,      Mkt_FTDI_Port )
         self.Set_Default( Mkt_Baudrate,  Mkt_FTDI_Baudrate )
         self.Set_Default( Mkt_LED_Template % 1, "12" ) # LED == P0.12
         self.HD44780( 2, 16, 23, 24, 22, 7 )
      if Board.Matches( Mkt_MT_2138 ):
         self.Set_Default( Mkt_Chip,      "lpc2148" )  # niet correct!
         self.Set_Default( Mkt_Xtal,      "14745600" )
         self.Set_Default( "cclk",        "58982400" )
         self.Set_Default( Mkt_Link,      Mkt_ARM_USB_OCD )
         self.Set_Default( Mkt_Port,      Mkt_FTDI_Port )
         self.Set_Default( Mkt_Baudrate,  Mkt_FTDI_Baudrate )
         self.Set_Default( Mkt_LED_Template % 1, "31" ) # LED == P0.31
         self.HD44780( 2, 16, 49, 51, 50, 55 )
      if Board.Matches( Mkt_MCB2130 ):
         self.Set_Default( Mkt_Chip,      "lpc2148" ) # niet correct!
         self.Set_Default( Mkt_Xtal,      "12 * MHz" )
         self.Set_Default( "cclk",        "60 * MHz" )
         self.Set_Default( Mkt_Link,      Mkt_ARM_USB_OCD )
         self.Set_Default( Mkt_Port,      Mkt_Serial_Port )        
         self.Set_Default( Mkt_Baudrate,  Mkt_Serial_Baudrate )
         self.Set_Default( Mkt_LED_Template % 7, "55" ) # LED7 == P1.23         
      if Board.Matches( Mkt_NDSi ):
         self.Set_Default( Mkt_Chip,      "lpc2148" ) # niet correct
         self.Set_Default( Mkt_Xtal,      "8 * MHz" )
         self.Set_Default( "cclk",        "48 * MHz" )
         self.Set_Default( Mkt_Link,      Mkt_ARM_USB_OCD )
         self.Set_Default( Mkt_GCC,       "devkitpro" )
         self.Set_Default( Mkt_Memory,    Mkt_ROM )
      if Board.Matches( Mkt_MC32USBST ):
         self.Set_Default( Mkt_Chip,      "PIC32MX795F512L" )
         self.Set_Default( Mkt_Xtal,      "8 * MHz" )
         self.Set_Default( "cclk",        "48 * MHz" )
         self.Set_Default( Mkt_Link,      Mkt_ARM_USB_OCD )
         self.Set_Default( Mkt_Port,      Mkt_Serial_Port )        
         self.Set_Default( Mkt_Baudrate,  Mkt_Serial_Baudrate )
         self.Set_Default( Mkt_LED_Template % 7, "55" ) # LED7 == P1.23         
         self.Set_Default( Mkt_GCC,       "PIC32GCC" )
                 
   def Debugger_Defaults( self ):      
      Memory = self.Get( Mkt_Memory )
      if Memory == None:
         return      
      if Memory.Matches( Mkt_RAM ):
         self.Set_Default( Mkt_Run, Mkt_Insight )
      if Memory.Matches( Mkt_ROM ):
         self.Set_Default( Mkt_Run, Mkt_Lpc21isp )   
         
   def Lpc21isp_Defaults( self ):      
      pass
      
   def Other_Defaults( self ):
      self.Set_Default( Mkt_Error_Handling, 1 )
      if self.Get_Value( Mkt_Link ) == Mkt_Simulator:
         self.Set_Default( Mkt_Xtal, "10 * MHz" )   
         self.Set_Default( Mkt_Run, Mkt_Insight ) 
      Xtal = self.Get_Value( Mkt_Xtal )
      CCLK = self.Get_Value( "cclk" )
      if CCLK == None:
         CCLK = Xtal
         self.Set_Default( "cclk", CCLK )
      PCLK = self.Get_Value( "pclk" )
      if PCLK == None:
         self.Set_Default( "pclk", "( %s / 4 )" % CCLK )
      Chip = self.Get_Value( "chip" )
      if Chip == "lpc2148":
         self.Set_Default( "fast_gpio", "1" )   
      if self.Get_Value( Mkt_Link ) == Mkt_Simulator:
         self.Set_Default( Mkt_Memory, Mkt_RAM )   
         
   def NDS_Defaults( self ):   
      self.Set_Default( Mkt_Emulator, Mkt_DeSmuME )
         
   def Activate_Defaults( self ):
      self.Set_Default( Mkt_GCC, "ArmDevEnv" )
      self.Set_Default( Mkt_Baudrate,  Mkt_Default_Baudrate )
      self.Board_Defaults()
      self.Debugger_Defaults()  
      self.Lpc21isp_Defaults()   
      self.NDS_Defaults()   
      self.Other_Defaults()   
      
class Docs( object ):
   "Miscalaneous documentation"
   
   def __init__( self ):
      pass

   def Build( self ):
      self.Blog()
#      self.FAQs()
      self.Misc()
      self.Asm_Intro()

   def Blog( self ):
      self.Documentation( """
         #article blog blog
         
         january 2007 : Time for the D3ESOT1 course, IIRC for the 4th time. 
         The basic ARM code I provide to the class is more structured now 
         than the previous years, and it has a name: ARM Realtime Kernel 
         (ARK). I keep writing new code, but I don't realy like the name. 
         
         may 2007 : The D3ESOT1 group is now working on their 'free' 
         projects (D3EEMS1).
         I give assistance for the 2TPRJ8 course, which uses Marten's 
         multiple-FSM style 'scheduler' on top of the low-level code I 
         wrote last year. A real pre-emptive scheduler might be more 
         appropriate.
         
         june 2007 : The name has changed to WAL, because I am vain, I don't
         yet have a kernel (= scheduler), and I hope to make much more than 
         just a scheduler. The various WAL code and header files are merged 
         into wal.wal and the awk scripts and the makefile do their magic.
         Documentation should be next to the code. Martin suggest to use 
         javadoc, which gives some usefull directions but of course I make
         my own format. wal.wal is ~ 90k and growing rapidly: text is more
         easily produced than code!
         
         february 2008 : D3ESOT1 again. WAL is far from ready for classroom 
         use. CORTEX-M3 seems to be the wave of the future, so I will have
         to study that. The STM32 chips look real nice. Name change: EasyARM.
         Let's see how long this name lasts... I got fed up with PsPad, 
         DevCpp seems a better alternative.
         
         april 2008 : D3EEMS1 and 2TPROJ8 again, maybe I can use EasyARM for
         D3EEMS1. DevCpp integration works reasonably well. 
         A pity I can't specify to include a makfile in a project template. 
         Code::Blocks will probably be the future, if it can provide the 
         list of project files to an external makefile. 
         Not sure about that yet. 
         The NSIS installer looks good, it should even be able to bundle
         other installers inside it, so I could make an all-in-one EasyARM
         with the compiler, Dev-C++, and all
         the other stuff. That is, if that is legally possible...
         The documentation formatter is sort of working.   
         Vista is a real PITA, so is (GNU)make's inability to deal with 
         spaces in pathnames. Installing EasyARM in C:\ solves both problems, 
         but I don't like it.
      
         june 2008: Documentation is a LOT of work. But the .html generation
         works, and Dev-C++ works, and the documentation is growing steadily.
         But not in time for use in this year's last courses.
      
         october 2008: Someone used the name "EasyARM" for an ARM board :(. 
         OK, maybe the limitation to ARM chips should be lifted anyway, so 
         the new name is "MicroKit". It seems to be free for this cointext. 
         I don't like the current AWK scripting and C applications, so I'll
         switch to Python for the glue.
         
         april 2009: 4 ARM assembler classes this year, and a new (USB) ARM
         board scheduled for 2009Q2, so I've done a lot of ARM work this year
         but not too much on the MicroKit. But the Python all-in-one 
         "application builder" is slowly taking shape (~ 4k lines now, 
         including whitespace), and I like it. I hope it won't turn out to be 
         too slow. In the process I also factour out the ARM=specific parts,
         it would be fun to support other 32-bit chips took (the Microchip
         MIPs would be a likely candidate). 
         
         april 10 2009: The application builder has run its first code! 
         It uses the ARMDevEnv tools, because I can't find an insight for 
         the CodeSourcery tools. For now it is fixed to RAM-only, the old
         LPC2148 board, and insight with the parallel-port wiggler, 
         but it is a start!
         
         april 17 2009: LPC2106 works, run from ROM works (using lpc21isp),
         Insight is auto-stared with the correct settings (unless there is
         a C:\tempd directory...). Character LCD works too, but display size
         configuration is not yet possible.
         
         may 06 2009: Webpage created, announced on LPClist and PICList 
         (but zero relevant reactions). HTML documentation generation works.
         mkt.py is ~ 8k lines, should now shrink a little.
         
         may 20 2009: hu_arboards v2,v3,v4 all work (LPC2106 & 2148), with
         wiggler, serial, and ft2232, both to ram and to rom. working on 
         KS0108 GLCD, serial seems to intefer! Documentation still needs 
         lots of work. Still zero outside feedback.
         
         june 13 2009: KS0108 and image import work. Configuration values
         are available in C. Next: T6963 graphics, font import, make
         configuration values available in Python. And lots of work on the 
         documentation.
         
         may 2010: The basic functions of the tool work pretty well. 
         It will be used in both the assembler and C++ classes.
         I made a hack so I can use Python classes as modules,
         all to make source folding in Notepad++ work.
         
         sep 2011: Mkt now supports Nintendo DSi development using 
         devKitPro, PAlib and the DeSmuME simulator, but as yet without
         the Mkt libraries.
         
      """ )
      
   def FAQs( self ):
      self.Documentation( """
         #faq what-is-mk What is MicroKit?

         MicroKit makes it easy (or let's say: somewhat less difficult) 
         to make application programs that run on 32-bit microcontrollers, 
         running 'bare metal' (without any Operating System present). 
      
         MicroKit integrates a number of tools, and provides a library 
         for chip initialisation and basic functions. 
         MicroKit uses on the GNU C and C++ compilers and the GNU assembler.
         An application can use any mix of these languages.
         A special file format can be used that supports
         the combination of C, C++ and assembler fragments, and
         MicroKit configuration, in one source file.
          
         The library tries to make it easy to start using the target 
         chips by shielding its novice users from ugly details 
         like oscillator settings and stack initialisation. 
         Experienced user might choose to take some or all 
         of these matters in their own hands.
      """ )
   
   def Misc( self ):
      self.Documentation( """
         #article introduction Introduction
         
         MicroKit is a tool that builds applications
         that run bare-metal (without a Operating System) on 32-bit
         microcontrollers using GNU assembler, C, or C++.  
         Typical targets are ARM7TDMI chips in the NXP (ex-Philips) 
         LPC series. 
         It uses the GNU tools (C and C++ compiler, assembler, debugger) 
         and some other tools (like lpc21isp, FlashMagic).
         Microkit compiles the sources, supplies initialization code
         and other libraries, links the application, and downloads it to
         the target.
         
         MicroKit is specifically aimed at the ARM novice. 
         The user can ignore the ugly and chip-specific details like 
         initialisation, timing, and I/O pin configuration. 
         This makes MicroKit suitable for a first course in ARM 
         programming, which is exactly what I use it for.
         But the advanced user can get full control over such 
         details, should he ever want to.
         
         Developing for an embedded target requires
         (besides the compiler and linker) also a tool to
         download your application to the target chip, and 
         maybe to one debug it. 
         MicroKit offers easy integration with such tools:
         integrated tools are launched (and if possible, run 
         fully automated) when the application has 
         been compiled and built.
         
         A simple MicroKit application can be very small. 
         It consists of a configuration part and a code part. 
         These parts can be in different files. In that case
         the configuration part can be like this:
      
         #code file examples/introduction/blink1.c
            #mkt configure board   keil_mbc2130
            #mkt configure memory  rom
            #mkt configure run     lpc21isp
         #end code   
         
         The lines that start with #mkt are handled by the MicroKit
         tool. Such lines are processed (and in this case, removed) 
         before the code is passed to the compiler.
         The first line configures the library for a
         #link mcb2130.
         This implies configuring for the appropriate chip 
         (an ARM LPC2138), the crystal (12 Mhz), etc. 
         It also makes some library routines available, 
         adapted for this board, like 
         #link mkt_leds_write. 
         The next line specifies that the application is to be build
         for loading into ROM (FLASH). The alternative is to load into RAM.
         The last line specifies the tool to be used to load the application
         into the target chip, in this case the 
         // #link lpc21isp
         lpc21isp bootloader.   
         
         #code file examples/introduction/blink1.c
            int main( void ){
               int dummy = 0;
               while( 1 ){
                  mkt_leds_write( ~ 0 );
                  mkt_wait_us( 1000 * 1000 );
                  mkt_leds_write( 0 );
                  mkt_wait_us( 1000 * 1000 );
               }
               return dummy;
            }
         #end code
        
         The C part of the application contains just the main function.
         The debugger automatically sets a breakpoint at the first instruction
         in the main. To keep this breakpoint out of the main, the
         first line is the intialisation of a dummy variable.
         Next is a neverending loop.
         This loop lights all LEDs, waits one
         second, blanks all LEDs, waits another second, and starts all over.      
         I prefer the expression 1000 * 1000 over the less readable
         1000000 (I can't quickly see whether the number of 0's is correct).
         The 'return dummy;' will never be executed, but it is required
         according to the C standard. A pity the standard commitee never realised
         that an embedded application has nothing to return to.
      
         I prefer to have all aspects of an application in one source text file.
         MicroKit supports this way of writing programs: 
         all parts of an application (configuration, headers, 
         assembler code, C code, C++ code) can be put in the same file. 
         Using this format the application would look like this:
          
         #code file examples/introduction/blink2.c
            #mkt configure board   keil_mbc2130
            #mkt configure memory  rom
            #mkt configure run     lpc21isp
            
            int main( void ){
               int dummy = 0;
               while( 1 ){
                  mkt_leds_write( ~ 0 );
                  mkt_wait_us( 1000 * 1000 );
                  mkt_leds_write( 0 );
                  mkt_wait_us( 1000 * 1000 );
               }
               return dummy;
            }
         #end code
                 
         The same example can be coded in ARM assembler. 
         This file is a bit longer, mainly because the loading of a parameter
         and the subroutine call are on separate lines, and I added white lines
         to separate the subroutine calls. Otherwise the code is the same.
         
         #code file examples/introduction/blink3.s
            #mkt configure board   keil_mbc2130
            #mkt configure memory  rom
            #mkt configure run     lpc21isp
            
               .global main
            main:
               ldr r0,=~0
               bl  mkt_leds_write
               
               ldr r0,=( 1000 * 1000 )
               bl  mkt_wait_us
               
               ldr r0,=0
               bl  mkt_leds_write
               
               ldr r0,=( 1000 * 1000 )
               bl  mkt_wait_us
               
               b   main
         #end code   
         
         The first two lines declare the 'main' label and make it accessible
         to other files (alternatively, MicroKit provides the
         #link ARM
         macro to do this is in one line).
         The body of the main consists of four pairs of lines.
         The first line of each pair loads R0 with an appropriate value,
         the next line calls a subroutine. The last line ('b main') jumps
         back to the start of the main.
      
         MicroKit has a number of limitations. 
         When your application's needs surpasses these limitations MicroKit is
         probably not a good choice for you.
      
         #list
            
         PC/Windows (XP, Vista) only.
         #break
         A Linux version is probably no big deal, 
         but currently I have no plans
         to develop and support a Linux version.
      
         ARM only.
         #break
         In the future Cortex-M3 will probably be supported, and maybe 
         Microchip PIC32, but I have no plans to support for instance
         Thumb mode or mixed mode (ARM-Thumb interworking).
         
         No C libraries.
         #break
         EasyARM does not include the common C libraries, with functions like
         printf. Some alternatives are provided, but they are primitive. 
      
         No dynamic memory management. 
         #break
         Memory can be allocated at run time, but not deallocated.
         If you feel you need full dynamic memory management 
         you might be able to do this yourself, but be aware of 
         the consequences (memory fragmentation, unpredictable timing).
      
         Limited range of chips and boards.
         #break
         The list of supported
         #link ea-chips chips
         and 
         #link ea-boards boards
         is currently very short.
         This will probably change in the future, but I make no promises.
      
         static choice of fast or slow GPIO.
         #break
         Both the use of the slow (legacy) GPIO access registers and the 
         faster registers available on newer LPC chips are supported. 
         By default the faster registers are used.
         The user can force the use of the slower register, but this
         choice is made in the configuration, 
         it can not be changed at run time.
      
         static choice of clock speeds
         #break
         The crystal, CPU and peripheral clock frequencies must be specified
         in the configuration. Dynamic (run time) changing of these
         frequencies is not supported.
         
         limited range of tools and interfaces
         #break
         Only a few tools andinterfaces are currently supported: 
         Insight/GDB with a parallel-port wiggler or FT2232 USB interface, 
         and lpc21isp with a serial port interface.          
         
         MicroKit can be used from a command line, but most users will 
         probably prefer an Integrated Development Environment (IDE). 
         Currently only one IDE is supported: PsPAD.
         // #link start-with-devcpp Dev-C++ 
         
         GCC only
         #break
         MicroKit uses the GCC tools.
         I did not attempt to avoid GCC-specific features. 
         There are some rumours that GCC would be a bad compiler for ARM chips,
         which seem to be based on a
         #link http://web.archive.org/web/20070205082028/http://www.keil.com/benchmks/carm_v0code.htm KEIL benchmark
         . Read 
         #link http://www.compuphase.com/dhrystone.htm The Dhrystone benchmark, the LPC2106 and GNU GCC
         for a comment.
         
         no exceptions
         #break
         Using exceptions with the GCC C++ ARM compiler causes more
         than 40Kb library code to be included. 
         Hence using exceptions is not supported.
         
         Nintendo DSi
         #break
         Mkt can be used to devlop for the Nintendo DSi, using devKitPro,
         PAlib, and the DesMuME simulator. In this casde the Mkt library is
         not used, and restrictions that are caused by this library do 
         not apply.
         #end list
         
      #article software license
      
         Copyright (c) 2008, 2009, 2010
            Wouter van Ooijen (wouter@voti.nl)
         
         Permission is hereby granted, free of charge, to any person obtaining a 
         copy of this software, to deal in this software in source text form 
         without restriction, including without limitation the rights to use, 
         copy, modify, merge, publish, distribute, and/or sell copies of the 
         software, and to permit persons to whom the software is furnished to do 
         so, provided that the above copyright notice, this permission notice,
         the next permission notice, and the disclaimer, appear in all copies.
         
         Permission is hereby granted, free of charge, to any person obtaining a 
         copy of this software, to compile and/or assembled this software, and to
         link the result, with or without other software, to an executable, and
         deal in that executable without restriction, including without limitation 
         the rights to use, copy, modify, merge, publish, distribute, 
         and/or sell copies of the executable, and to permit persons to whom the 
         executable is furnished to do so.
      
         THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
         WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
         MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
         ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
         WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
         ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
         OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      
         Note that this license applies to the software, not to the documentation.
         
         
      #article documentation license   
         
         Copyright (c) 2008, 2009, 2010 
         Wouter van Ooijen (wouter@voti.nl)
         
         Permission is hereby granted, free of charge, to any person obtaining a 
         copy of this documenation, to redistribute this documentation in its
         original (electronic) format, and to make paper copies of it for his or
         her own use.
         
         Note that this license applies to the documentation, not to the software.
         
         
      #article todo ToDo list
         #index known limitations, limitations, todo
         
         #end list
      
      #article arm-dbxxx ARM DBxxx board
         LCP2378 (LQFP100) - lukt dat
         SD/MMC card interface
         Ethernet 10/100 interface
         I2S interface to a DAC TDA1543 - also ADC?
         TDA8425 (I2C) - connects to TDA1543 and PWM outputs
         L6204 dual H bridge
         12V accu input -> L6204, 7805
         LCDs: 2x16, 4x16, 128x64
         4x4 keys, external keypad
         I2C: TCN75, EEPROM
         PS/2 external connector
         I2C external connector
         1-wire external connector, DS18S20
         coin battery, 32kHz xtal
         USB can power - except H-bridges
         USB1 to chip
         USB2 FTDI232RL to bootload
         2 potmeters
         2 (aansluitingen voor?) rotaries met pushbutton
         een paar joystick-type buttons
         seriele poort naar RS485 - kan bord voeden!
         7-segment displays
         IR ontvanger
         LDR
         IR zend LED
         8 LEDjes direct op I/O pinnen
         8 LEDjes via I2C
         LED matrix (gemultiplext)
         LM335 analog temperature sensor
         TL431 2.5 Volt  voltage reference
         audio input/outpouts via jacks
         12V audio LSP output?
         on-board speaker
         SPI connector(s)      
            
      #article license
      
      //===========================================================================
      
         The license for the EasyARM library software allows you to use the 
         library in your application, without any legal consequences. 
         If you want, you can even change the library code, and still use
         it in your application, without any consequences. You don't need
         to publish your modifications, and you certainly don't have to publish
         the software that you link with the library. 
         
         This is in my opinion as free as a license can be for a software 
         developer. Anyhthing less (even a requirement to mention that the 
         library is part of your application) can cause big trouble for an
         embedded application. Think of a greeting card with a Happy Birthday
         melody that has to "mention" all condtributing software parts, before
         the melody can start...
         
         The license for the library software in source form has one restriction:
         when you provide the library (in source form) to anyone else, it must
         be under the same license conditions. This also applies to any 
         modifications you make, but only if you choose to provide those 
         modifications to anyone else in source form. If you want to keep
         them private, fine.
         
         The summary is that use of the library in a product 
         (which contains an excutable application) is totaly free, 
         but distribution of the library itself (as source) is allowed 
         only under the same license.
      
         The license for the documentation is more restricted. You are allowed
         to distribute the unmodified documentation in the original format,
         and you are allowed to make a paper copy for your own use. 
         If you want more you will have to contact the author for permission.
             
      #article installation Installation
       
         MicroKit should work on Windows XP and Vista machines.
         The installation requirements vary a bit depending on
         the IDFE and target you want to use.
         To use MicroKit:
          
         #list
          
            [for ARM9TDMI chips] download and install the 
            #url http://www.voti.nl/ARMDevEnv.exe ARMDevEnv
            (to its default location: C:\Program Files\ARMDevEnv)
            
            [for the Nintendo DSi] download and install 
            #url hhttp://sourceforge.net/projects/devkitpro/ devKitPro
            (to its default location: C:\devKitPro)
            
            [for the Nintendo DSi] download and install 
            #url http://palib-dev.com/downloads.html PAlib
            (to its default location: C:\devKitPro)
            
            [for the Nintendo DSi] download and install 
            #url http://palib-dev.com/downloads.html DeSmuME
            (to C:\devKitPro\sim\DeSmuME)
            
            download and install 
            #url http://www.python.org/ftp/python/2.6.2/python-2.6.2.msi \
            Python 2.6.2
            (to its default location: C:\Python26; 
            it will probably work with other Python versions, including 3.1)
            
            download and install the 
            #url http://sourceforge.net/project/downloading.php?group_id=78018&filename=pywin32-212.win32-py2.6.exe \
            Python for windows extensions
            (This is the version for Python 2.6.x, you must use 
            a version that matches your Python version.)
            
            [when you want to use the mkt image converter] 
            download and install the 
            #url http://effbot.org/downloads/PIL-1.1.6.win32-py2.6.exe PIL
            (this is the version for Python 2.6.x, you must use 
            a version that matches your Python version.
            currently no PIL seems to be available for > Python 2.6;
            AFAIK there is no PIL yet for Python 3.0 or higher)
            
            download 
            #url ./mkt.py mkt.py 
            and put it in the directory where your source file(s) are 
            (as yet there is no install for mkt.py, just copy it to 
            every place where you use it)
            
            [for serial downloading to the flash memory of an ARM chip]
            download 
            #url ./lpc21isp.exe lpc21isp.exe
            and put it somewhere in your PATH, 
            C:\\Program Files\\ARMDevEnv\\bin would be a good place 
            
            [if you want to use this IDE] download and install
            #url http://www.pspad.com/en/download.php psPad
            
         #end list
         
      #article use Use
         #header with-armdevenv Using MicroKit with the PsPAD editor
      
         To use MicroKit with the PsPAD editor (part of the HU ARMDevEnv):
         
         #list
         
            make sure you have installed all items as mentioned in 
            #link installation
            
            put a copy of mkt.py in the directory where 
            your source file(s) and the pspad .dev file are   
            
            Put a copy of the MicroKit Makefile for the 
            ARMDevEnv in the directory. 
            Running the DOS command "mkt.py -pspadglue"
            in the directory where your sources are will create 
            this Makefile.
            You must copy this Makefile 
            (and the mkt.py file, and of course a .dev file)
            to every new directory where you want to build a project.
            
            Now you can double-click on the .dev file and use the PsPAD
            environment as you did before. 
            
            By default the HU ArmDevEnv uses a linkerscript and a crt0.s 
            file. MicroKit supplies such files automatically, hence            
            the crt0.s file must be removed from the list of project files.
            
         #end list   
         
            Somewhere in your source files you must specify the 
            configuration information that MicroKit needs. 
            I suggest you do this at the top of the file
            that contains your main funtion (or subroutine).
            You can use these lines to run on a HU ARM board in ARM, 
            using the Insight debugger:
            
            #code
               #mkt configure board   hu_arm_v4
               #mkt configure memory  ram
            #end code      
            
            Or use these lines to download your application to
            the FLASH of the board:
            
            #code
               #mkt configure board   hu_arm_v4
               #mkt configure memory  rom
            #end code      
            
            This requires that the virtual serial port is COM4.
            I suggest that your rename the virtual serial port to COM4.
            If you don't want to do this you can specify the serial port
            explicitly. Lpc21isp seems to be unable to use port numbers
            higher than 4.
            
            #code
               #mkt configure board   hu_arm_v4
               #mkt configure memory  rom
               #mkt configure port    COM2
            #end code                  
            
            For the Nintendo DSi you can use these lines:
            
            #code
               #mkt configure board      ndsi
               #mkt configure emulator   desmume
            #end code      
         
         #list
         
            For assembler code: make sure you have used the
            appropriate 
            #link memory-sections memory directives 
            to put the code and data
            in the appropriate sections.
            
            Change the "#configure memory ram" directive to 
            "#configure memory rom".
            
            Add a directive like "#configure port COM1",
            where COM1 is replaced by the actual serial port
            that your board is connected to. For a real
            serial port this will likely be COM1, but for
            an USB-simulated serial port the PC will choose
            the serial port number. For lcp21isp you must change
            this number to a number in the range 1..4. 
            I prefer 4. To do this start the Device Manager
            (start -> Control Panel -> System -> Hardware -> Device Manager).
            Expand ports (COM & LPT) and double-click on the UBS-serial port.
            Choose Port Settings -> Advanced. Now you can change the
            port number to COM4. 
            The PC will probably complain that this port is in use, but
            if you currently have no COM4 present you can do this safely.
            Sadly, this setting will be effective only for this particular 
            USB-serial converter, and when plugged into its current USB
            connection. 
                        
            Rebuild your application. Click the debugger icon. 
            This will start the lpc21isp downloader.
            When the downloading is completed your application 
            starts automatically.
         
         #end list
         
         #header mkt-cmd Using MicroKit on the command line
         
         The MicroKit tool itself is a command line application.
         The simple way to use it directly is to specify the
         source file(s) that make up your application. The tool
         will build your application, and (if the build was
         completed succesfully) download and run it. 
         If you just want to build you can add the "-build" option, 
         if you just want to download and run an application you just built
         you can use the "-run" option.
         
         If you just want to upload an image file (.bin or .hex) to ROM
         you can specify that image file (and no source files). 
         In thus case you must also specify at least the chip, 
         xtal frequency and serial port on the command line.
         Alternatively, you can specify the board, which implicity
         specifies the chip and xtal frequency: 
         
         #literal
            mkt.py image.bin chip=lpc2148 xtal=12000000 port=com4 
            mkt.py image.hex board=hu_arm_v4 port=com4 
         #end literal
         
         For all source and image files specified on the command line the
         file extension can be omitted, provided that only one 
         file with a suitable extension is present. 
         This file name cleverness can be disabled by using the 
         option "-noclever".
         
         Microkit does not write anything to the directory it runs from: 
         all temporary files and result files are written to the directory 
         C:\_mkt_temp. 
         In normal use this will not be visible to the user, 
         but it has the benefit that when MicroKit is run from an 
         USB stick (which is normal practice in a classroom) 
         writing to the USB stick (slooooow) is avoided.

         People have critisized me for using a fixed temporary 
         directory location. 
         I would like to change this to a system-defined location, 
         but the problem is that I need the real pathname of such 
         a location (in the correct case), and so far I have not 
         found a way to obtain this on Windows. The tempfile.gettempdir() 
         function does return the system-defined temporary directory, 
         but not always in the correct case, it might for instance 
         return C:\TEMP on a system where (only) c:\temp exists. 
         If you know how to solve this please let me know!

         Command-line options and parameters:
         COMMAND-LINE

         #header configuration Configuration
         
         MicroKit must be configured for the target hardware
         you use to run your apllication on. The easiest option is
         to use one of the supported
         #link boards.
         If you don't, you must configure at least
         
         #list
         
            chip: the target chip that you use. Choices are:
            CHIPS.
            
            xtal: the main crystal that you use. You can use the
            abbreviation '* MHz' to make this a bit more readable.            
            
         #end list
         
         By default the CPU will run the frequency of the crystal.
         The LPC chips have an on-chip PLL (Phase Locked Loop) circuit
         that can derive a different CPU clock from the crystal frequency.
         You can configure this cclk frequency. The startup code
         will configure the PLL to generate this clock (provided
         that this is possible). 
         
         By default the peripherals in an LPC chip run at a clock that is
         the same as the CPU clock. Alternatively, you can specify this
         pclk (peripheral clock) to be half or a quarter of the CPU clock
         (this saves some power).
         
         You must always specify whether you want the application to be
         built for ROM (FLASH) or for RAM. 
         When you specify ROM the default download/debug/run tool is 
         lpc21isp at 19.2 Kb.
         When you specify RAM the default download/debug/run tool is
         Insight, using a parallel-port wiggler connected to LPT1.
         
         The example configuration below illustrates these options. 
         The first three lines are mandatory, the rest is optional.
         
         #literal
            #configure memory  rom
            #configure chip    lpc2106
            #configure xtal    10 * MHz
            
            #configure cclk    60 * MHz
            #configure pclk    30 * MHz
            #configure run     insight
            #configure port    lpt1
         #end literal
               
      #article installation-x Installation
      
         The EasyArm environment uses the CodeSourcery GCC ARM compiler
         and Insight/GDB debugger, 
         and offers (optional) integration with some smaller components.
         It is possible to use EasyARM directly, but it is 
         much easier to use an IDE. Currently only the DevC++ IDE is supported.
         Integerating these packages into one installer package
         creates some legal and technical problems, 
         so you must download and install these packages yourself. 
         An advantage is that you can upgrade each package separately.
      
         First download the GCC ARM compiler package from
         #url http://www.codesourcery.com/gnu_toolchains/arm/download.html. 
         Select the ARM EABI, for IA32 Windows, without sources. 
         I got a file named arm-2007q3-53-arm-none-eabi.exe .
         Run it. The first installation screen has the strange habit to
         hide under an explorer window. Use the default settings:
      
         #list
            Select the "Typical" install set.
            
            Use the default location 
            ("C:\Program Files\CodeSourcery\Sourcery G++ Lite"),
            
            The default is to set the path for the current user only.
            EasyARM does not need the path to be set, so it for EasyARM is
            does not matter what you choose, but for your convenience you 
            might want to modify the path for all users.
            
            Creating an icon is not necesarry either, 
            but it is the default and again you might want to do this anyway.
         #end list
               
         If you want to use a different version of the Insight debugger
         than the one that comes with Code Sourcery you can do so,
         but the Code Sourcery version seems to work fine.      
         I tested the Insight from
         #url http://sourceforge.net/projects/devkitpro/ DevkitPro 
         files area at
         #url http://sourceforge.net/project/showfiles.php?group_id=114505.
         Take the lastest Insight for i386 / windows. 
         I got a file named insight-6.8.50-20080308.exe.
         Run it. It will ask for a location to unpack to,
         specify "C:\Program Files" (it will unpack to C:\Program Files\insight).
         You will have to change one line in the Makefile.mkx in the EasyARM
         directory to use a separate Insight. Seach for Insight and you will
         find it.
         
         A number of tools can be used to download an application
         to NXP (ex-Philips) LPC chips. You you might want to 
         install one or more of these.
         #list
            #paragraph The Philips Flash Tool. 
            I found the latest version, V2.2.3, at
            #url http://www.standardics.nxp.com/support/documents/?type=software
            (the direct link was 
            #url http://www.standardics.nxp.com/support/documents/microcontrollers/zip/flash.isp.utility.lpc2000.zip). 
            Install it using the default settings.
            
            The FlashMagic tool, you can find it at
            #url http://www.flashmagictool.com/. 
            Install it using the default settings.
         #end list
      
         Download the EasyArm package and unpack it to 
         its default location: "C:\Program Files\EasyARM".
         
         If you want to use Dev-C++ (Dev-Cpp) as IDE you can get it from 
         #url http://www.bloodshed.net/devcpp.html. 
         I used Dev-C++ 5 beta with Mingw/GCC 3.4.2.
         (note: You must get the version *with* compiler.)
         I got the file devcpp-4.9.9.2_setup.exe.
         Install it to its default location (which is "C:\Dev-Cpp").
         If you copy the files in the EasyARM\Dev-Cpp\templates directory to the
         Dev-Cpp\templates directory (there is an install.bat file
         in the EasyARM\Dev-Cpp directory that does this) you
         can select EasyARM templates when you create a new project.
         
         //If you want to use Code::Blocks as IDE you can get it from 
         //#link http://www.codeblocks.org/downloads/5
         //I used 8.02 (with MinGW).
         //I got the file codeblocks-8.02mingw-setup.exe .
         //Install it to its default location (which is "C:\Dev-Cpp").   
         
         Next you might want to read 
         #list   
            #paragraph #link start-with-devcpp    
            //#paragraph #link start-with-codeblocks  
         #end list
         
      """
         .replace ( "CHIPS", "lcp2106, lpc2148" )
         .replace( "COMMAND-LINE", Command_Line_List() )
      )

   def Asm_Intro( self ):
      self.Documentation( """
      #article asm-intro A short introduction to ARM assembler

          This introduction is specific to assmbler as used in MicroKit:
      
          #list
            
             AS, the GNU assembler
      
             used for the ARM 
             
             with the assembler-with-preprocessor option enabled 
      
          #end list   
      
          Other assemblers and/or 
          assemblers for different chips will differ in details.
          
          The instruction set described here is the ARM7TDI-S instruction
          set, as used in the popular LPC chips. Newer ARM chips can handle
          these instructions, but might support a few more.
      
          Assembler is a line-oriented programming language: basically
          each line is translated by itself,
          and generates zero or more values that are to be placed in memory
          at what is called the current location, after which the current
          location is incremented so it points to the next (free) location.
          Where exactly the values are placed in the chip's memory
          is up to the linker: the assembler writer does not know and
          should not care. If he needs to use the address where something 
          is placed he can use a label (explained below).
      
          Each line generates value(s) for a specific section. The three
          important sections are TEXT, BSS and DATA:
      
          #list
      
             The TEXT section
             is for machine instructions and read-only data. 
             When running from ROM the TEXT section will be placed in ROM.
      
             The BSS section is for data that does not need a specific 
             initial value. When running from ROM the BSS section
             is placed in RAM.
             The startup code (supplied automatically) clears the
             BSS section (all memory locations are filled with 0).
      
             The DATA section is for read-write data that needs a specific 
             initial value. 
             When running from ROM the DATA section itself is placed in RAM, 
             but a copy of the initial values is stored in ROM. 
             The startup code copies these initial values from ROM to RAM.
             
         #end list
         
         When running from RAM the distinction between TEXT and DATA is lost.
         The BSS segment is still initialized with 0 
         before your application starts.
      
          An at-sign '@' or a slash-slash '//' starts a comment. 
          That sign and the rest of the line is ingnored. C-style block 
          comments (start with '/*', end with '*/") are also ignored.
          All other C preprocessor constructs (#define, #if, #include, etc)
          are also supported too. 
          Lines that are empty (after removing comments) are ignored.
      
         When the first word on a line has a colon ':' after it that word
          is the definition of a label. 
          Such a word can be used in the assembler program 
          (both after its definition and - unlike C - 
          also before its definition) and will then be replaced 
          by the address of the 'current location' at the place of the label. 
          In practice this means that it is the address of the 
          next 'thing' following the label in your program.
          Labels are case-sensitive.
         The convention is that labels start in the first column, and
          assembler instructions and directives do not.
      
          Constant values can be expressed in a number of ways:
      
          #list
             Literal values: decimal, hexadecimal (prefixed with '0x'),
             or a character value (a single character enclosed in single
             quotes).
      
             Labels: a label name is replaced by the corresponding
             memory location.
      
             Expressions: all C operators (+,-,*,%,/,<<, >>,&,|,^, etc)
             can be used to build more complex expressions from
             literal values and labled names.
          #end list
      
         Except for comments and labels each non-empty line contains 
          either an ARM instruction or an assembler directive. 
          Directives start with a point '.', assembler instructions start
          with a letter. De most important directives are:
      
          #list
      
             .global : 
             This directive must be followed by a (comma separated) list of
             labels. By default assembler labels are visible only in the
             file in which they are defined. The labels mentioned in a 
             .global directive are visible to all other files in the project.
      
             .byte :
             This directive is followed by a (comma separated) list of values.
             The values are placed in sucessive memory locations, occupying
             one byte each.
      
             .word :
             This directive is like the .byte directive, but each value 
             occupies a word (4 bytes)
      
             .ascii :
             This directive is followed by a double-quote delimited string.
             Each letter of this string is placed in a successive 
             memory location.
      
             .asciz :
             This directive is like the .ascii directive, but an extra 0
             byte is added at the end of the string of bytes.
      
             .align :
             This directive skips as many memory locations as required to
             make the memory address (where the next item will be placed)
             a multiple of 4.
      
             .skip :
             This directive is followd by a number. It skips that number
             of memory locations.
      
             .arm :
             These directives indicates that, untill specified otherwise,
             the following assembler instructions are ARM (not Thumb)
             instructions. 
             
             .code :
             This directive indicates that, until specified otherwise, 
             the following lines are to be placed in the CODE section.
      
             .data :
             This directive indicates that, until specified otherwise, 
             the following lines are to be placed in the DATA section.
      
             .bss :
             This directive indicates that, until specified otherwise, 
             the following lines are to be placed in the BSS section.
      
          #end list
            
          The ARM chip has 16 register, R0 ... R15. 
          Each register is 32 bits wide.
          R0 .. R12 are
          general-purpose registers that can be used by the application
          in any way it likes (but the C compiler can use R8 for 
          a specific purpose).
          Registers R13, R14 and R15 have a special purpose. They
          are preferrably used by their alternate names: SP, LR and PC.
          SP is the Stack Pointer, PC is the Program Counter, LR is the
          Link Register.
      
          Each ARM assembler instruction is 32 bits (1 word, 4 bytes).
          Instructions must start on an address that is a multiple of 4.
          What happens when you don't align instructions is not defined.
          The LPC chips seems to reset when an unaligned instruction is
          executed.
      
          In most ARM instruction the information (data) flows from right 
          to left, just like in a C assignment statement.
          The STR and STM instructions are the exceptions: in these 
          instructions the data flows from left to right.
      
          There is no single instruction to load a constant 32-bit value 
          into a register (why not?). Instead the assembler offers a 
          fake instruction that translates into an assembler instruction and
          a data word. The format of this instruction is
      
          #code
             LDR register, =value
          #end code
          
          The register can be any of the registers R0 .. R15, or one 
          of the alternate register names SP, LR, PC.
          The value can be any constant expression.
      
          The ARM is a register-register architecture: there is a strict
          separation between instructions that do calculations, and
          instructions that do memory access. The memory access instructions
          can load a 1, 2 or 4 byte value into a register, or store
          such a value from a register into a memory location.
          The format of these instructions is 
      
          #code
             LDRs destination, [ address ]
             STRs source, [ address ]
          #end code
      
          The destination, source and address must be registers. The
          s is an optional size specification: it can be B for a byte,
          H for a half-word (2 bytes) or omitted for a word (4 bytes).
          For a word load or store the address must be a multiple of 4,
          for a half-word it must be a multiple of 2.
          What happends wghen you load or store to an unaligned 
          address is not defined. On LPC chips such a load can (often?)
          produce the 'correct' result.
          
         When a byte or a half-word is stored the higher bits in the source
          register are ignored. When a byte or half-word is loaded
          the remaining bits in the register are filled with copies
          of the highest loaded bit. This is called sign extension: 
          it preserves the 2s-complement value.
      
         There are 3 variations of the load and store instructions.
          The first one adds an offset to the address register 
          (without changing the address in the register):
      
          #code
             LDR destination, [ address, #offset ]
             STR destination, [ address, #offset ]
         #end code
            
          The second variation is like the first one but with an exclamation 
          mark after the instruction. The effect is that the offset is added
          to the address register (thus updating the address register), and
          this new address register value is used as address:
      
          #code
             LDR destination, [ address, #offset ]!
             STR destination, [ address, #offset ]!
         #end code
      
          The third variation first uses the addres that is in the 
          address register, and after that it adds an increment 
          (a constant value) to that addres register:
      
          #code
             LDR destination, [ address ], #increment 
             STR destination, [ address ], #increment 
         #end code
      
          The offset or increment must be a constant expression.
          
         The load (and store) *multiple* instructions can read or write
          a set of registers in one instruction. 
          The address of the memory region is supplied by (another) register. 
          This register can contain either the highest of the used addresses 
          (hence the successive addresses that are used will be decending) 
          or the lowest (ascending).
          Additionally, the address register can contain either the first
          address to be used, or one step beyond the first location.
          Combining this with loading and storing this produces 8 variations:
          LDM or STM for load or store, E or F for Empty or Full, 
          D or A for Descending or Ascending:
          LDMFD, LDMED, LDMFA, LEMEA, 
          STMFD, STMED, STMFA, LEMEA. 
      
          These load and store multiple instructions are mostly used to 
          implement a stack.
          The convention is to use a stack that grows down (from a
          high memory address to lower memory addresses), and to
          have a stack pointer in R13 (hence its name SP) that points
          to the lowest memory location that is in use (Full). Hence the
          assembler mnemonics that are commonly used are STMFD and LDMFD.

    The B (branch) instruction is what other processors call
    a jump or a goto: it causes the execution of instructions
    to continue at the label after the B. The BL (branch and link)
    instruction is what other processors call the call or gosub:

          
          To Be Written: B, BL, conditions, LR trick, arithmetic, S
         
      """ )   
   
   def xIntroduction( self ):
      self.Documentation( """
         #article start-with-devcpp Using Dev-C++

         You can either create a new project, or (preferred) use an existing 
         (empty) project as start.
         
         To use an empty project as start (this is the preferred way
         to start) you can copy one of the EasyARM\Dev-Cpp\projects\empty-*
         directories. Your new directory must *not* contain spaces in
         its pathname, so for instance a folder on the desktop is not a good 
         place for a project.
         
         The empty-asm, empty-c and empty-cpp projects use separate
         files for the configuration (config.mkx) and for the code
         (main.asm, main.c or main.cpp). 
         The empty-ea project uses one file (project.mkx) that
         contains both the configuration and the code.
         I prefer this 'combined' format, but your taste might differ.
         In the directory you created you can double-click the project.dev file
         to start Dev-C++ with your (empty) project.   
         
         If you realy want to start a new project from scratch:
         #list
         first Start DevC++. 
         It can be found in your Programs list under "Bloodshed Dev-C++".
            
         Choose File > New > Project.
         (No, you can not start a new project from the Project entry...)
         If you did install the EasyARM templates you will see an EasyARM
         tab, which provides a some EasyARM templates. 
         
         Choose the one that seems appropriate,
         for instance "EasyARM C/C++". Select C or C++, which will
         affect only the name of the main source file (main.c or main.cpp).
         If you choose "EasyARM assembler" or "EasyARM .mkx format" 
         the C/C++ selection will have no effect.
         
         Save your project files, be carefull to select "all known files (*.*)"
         when saving the makefile.mak and config.mkx files, otherwise 
         they will be named makefile.make.cpp and config.mkx.cpp, 
         which will cause trouble later when you try to build your project.
         
         Now there is one more thing to do: you must configure your new
         project to include the EasyARM makefile.mak in the Dev-C++ 
         Makefile. Choose Project > Project Options (Alt-P). 
         Select the Makefile tab. Click the bottom icon at the right side
         (it is the only active button) and select the makefile.mak. 
         Do not forget to click the (now active) Add button to realy
         add this file to the list of to-be-included files. 
         Its name will be moved to the list.
         Click OK to confirm. 
         
         Your project is now configured
         to use EasyARM. This configuration is saved in the 
         .dev file that was created for your project.   
         
         #end list
         
         When you want to ressume working on a project you
         can double-click the .dev file and Dev-C++ will open.   
         
         #image devcpp-01.gif
         
         Dev-C++ is a simple Integrated Development Environment (IDE).
         At the left side it has a project window that shows the files 
         in your project. To the right is the edit window, with tabs along
         the top for the files that are open. The usuall editing
         operations are available. 
         
         The project window shows the list of source files that comprise 
         the project. 
         New files can be added by right-clicking on the project name at the top
         ('blink' in the screenshot), files can be deleted from the project
         by right clicking on the file. Deleting a file from the project will
         not delete the file itself.
         Files that are present and/or open in the editor, but not mentioned 
         in this files list, will not be used for building the application. 
         It is strongly advised to keep all project files in the same directory.
         
         The four buttons 
         #image devcpp-02.gif
         in the second button row are used for the building process. 
         Dev-Cpp is meant to be an IDE for developing PC programs, 
         so a trick is used to make a correspondence between these buttons 
         and the building of an ARM application. What the IDE does
         when it performs a build is a two step process:
         
         #list
         
         First the embedded application is built. 
         
         Next a small PC application is built that, when run, will 
         start the ARM tool that is specified in the configuration.
         
         #end list
         
         This PC application is what Dev-Cpp sees as the result of the
         building process, so this application is what is started when 
         the IDE starts a 'run'. Debugging this PC application makes
         little sense, so the debug button should not be used.
         
         The build an run buttons behave as they should: they
         build the embedded application and the PC application, and
         the run button also starts the PC application.
         
         The effects of the available buttons is summarized below:
         
         #list
         
            #image devcpp-03.gif
            (single compile) : 
            In Dev-Cpp this button compiled the single file that was
            open in the editor.
            With MicroKit this button builds the applications
            (same effect as the 'build all' button).
            
            #image devcpp-04.gif
            (run) : In EasyARM this will
            start the tool that was configured for downloading 
            and/or starting (or simulating) the application.
            
            #image devcpp-05.gif
            (compile and run) : 
            Build the applications and start the configured tool.
            
            #image devcpp-06.gif
            (build all) :
            Build the applications.
            
            #image devcpp-07.gif
            (debug) :
            With MicroKit this would debug the PC application, with is not
            very usefull. Don't use this button. When you want to debug
            the embedded application you must configure the appropriate tool
            (for instance
            #link insight).
            The tool will be started automatically when Dev-C++ starts
            the application.
            
         #end list
   
      """ )
   
   def xIntroduction( self ):
      self.Documentation( """
 #article start-with-codeblocks starting with Code::Blocks   

   to be written (maybe not possible at all)

      """ )
   
   def xIntroduction( self ):
      self.Documentation( """
 #article ea-license MicroKit license
   #index license
   
      MicroKit consists of the library itself, a makefile, some small
   awk scripts used by the makefile, a linkscript, and a set of chip 
   header files.
   
   todo
   
      """ )
   
   def xIntroduction( self ):
      self.Documentation( """
 #article ea-tree MicroKit directories and files
   #index directories, files

   limited use of standard C libraries
   todo

      """ )
   
   def xIntroduction( self ):
      self.Documentation( """
 #article ea-makefile MicroKit makefile
   #index makefile
   
      """ )
   
   def xIntroduction( self ):
      self.Documentation( """
 #article fixed-bugs fixed bugs
   
      """ )
   
   def xIntroduction( self ):
      self.Documentation( """
 #article ea-file-format MicroKit .mkx file format
   #index section, #section

   An .mkx file can contain configuration, headers, and code.
   The code can be in assembler, C, or C++. 
   The makefile uses AWK scripts to extract 
   the appropriate headers code parts when needed. 

   Configuration lines in a .mkx file look like C #define lines, but
   start with #configure instead of #define. The makefile 
   
   #list
   
      gathers all such lines (from all .mkx files in the project)
   
      checks the #configure'd names 
      
      replaces #configure by #define, 
      to produce the project configuration.
      
   #end list
   
   This (temporary) project configuration file is used to compile the ea 
   library itself.
   It is also included by the ea.h file (which should be included by all 
   project source files), so the configuration is also available to the 
   application, but in most cases you will not need to use it directly.
   
   Note that you could use plain #define lines in the configuration 
   sections, but this would bypass the checking of the #define'd names.

   Each source code section in an .mkx file starts with a #section line 
   (which must start in column 0). 
   #list
   
      "#section header" :
      #break
      This starts a headers section. 
      In the traditional use of files
      the text of such sections would be in a .h file. 
      Note that the headers must be useable by C, C++ *and 
      assembler*. All function declaration use the "C" designation, 
      this makes it possible to call the functions from both C and C++.
  
     "#section assembler" :
     #break
     This starts an assembler section. 
     In the traditional use of files
     the text of such sections would be in a .s file.
  
     "#section c" :
     #break
     This starts a C code section.
     In the traditional use of files
     the text of such sections would be in a .c file.
  
     "#section c++" :
     #break
     This starts a C++ code section. In the traditional use of files
     the text of such sections would be in a .cpp file.

  #end list

  The MicroKit library itself contains code and headers, and also
  the documentation.
  A Python program extracts the documentation parts and generates 
  documentation in .html format.
  The format of this documentation is not described here. 
  Check the _make_documentation.py script if you are interested.

      """ )
   
   def Introduction( self ):
      self.Documentation( """
 #article acps ARM procedure call standard
   #index AAPCS, saved registers, call standard

   The Easy RAM library code adheres to the procedure call standard 
   for the ARM architecture:
  
   #literal
       R0 = a1 : argument 1 / result 1 / scratch register
       R1 = a2 : argument 2 / result 2 / scratch register
       R2 = a3 : argument 3 / result 3 / scratch register
       R3 = a4 : argument 4 / result 4 / scratch register
       R4 = v1 : variable register 1
       R5 = v2 : variable register 2
       R6 = v3 : variable register 3
       R7 = v4 : variable register 4
       R8 = v5 : variable register 5
       R9      : platform-dependent
      R10 = v7 : variable register 7
      R11 = v8 : variable register 8
      R12 = IP : used by the linker
      R13 = LR : used as Link Register
      R14 = SP : used as (full-descending) Stack Pointer
      R15 = PC : used as Program Counter
   #end literal
  
   R0 - R3 are used to pass arguments into a subroutine and to 
   return results. Within a subroutine these registers can be 
   used to hold intermediate results, but only between subroutine 
   calls: a called subroutine is not obliged to preserve the values 
   in these registers.
   
   R4 - R8, R10, R11 are used in a subroutine to hold intermediate 
   results. A called subroutine must preserve the values in these 
   registers.

   The use of R9 is platform dependent. 
   MicroKit code does not touch R9.

   R12 can be used by the linker to implement a call from one 
   subroutine to another. Hence this register can be used by a 
   subroutine to store intermediate results, but only between 
   subroutine calls (like R0 - R3).

   #link AAPCS http://www.arm.com/pdfs/aapcs.pdf - TBW
      
      """ )
   
   def Introduction( self ):
      self.Documentation( """
 #article ea-coding-style MicroKit library coding style
   #index coding style, style, format

   MicroKit library is optimized for small code size. 
   This specifically means that library functions that are not used 
   should not generate code or occupy data space. 
   Library features that are likely to be used on small chips
   should be optimized for code and data size. For features
   that are not likely to be used on such chips (for instance
   USB functions) is requirement is loosened.
   
   The second optimization is for ease of documentation, which
   is almost the same as ease of use.
   
   TBW naming convention, case      

      """ )
      
   def Global_Header():
      self.Documentation( """      

#article kHz MHz, Kb, Mb
   #index kHz, MHz, Kb, Mb
   
   The MicroKit header defines marcros for some common quantity mnodifiers.
   Note the difference between the scientific k and M and the
   K and M used with memory sizes.   
   
   #literal
      #define kHz ( 1000 )
      #define MHz ( 1000 * 1000 )
      #define Kb  ( 1024 )
      #define Mb  ( 1024 * 1024 )
   #end literal
   
   // tbw example

 once: #section headers

   #define kHz ( 1000 )
   #define MHz ( 1000 * 1000 )
   
   #define Kb  ( 1024 )
   #define Mb  ( 1024 * 1024 )      
   
      """ )

class Chip_Peripherals:
   "Peripheral base class"
   ""
   "NOTE: this class is used as a module"
   
   class Register:
      "a single (often 32-bit) register, often part of a perihperal"
      "   name   : name of the register "
      "   offset : offset from the preripherals base address "
      
      def __init__( self, Name, Offset ):
         self.Name = Name
         self.Offset = Offset
   
   class Peripheral:
      "a peripheral, consists of a number of registers"
   
      # name   : name of the peripheral, used as prefix for it's register names
      # record : 
      # text   : full name of the peripheral, used only in comments
      # base   : base address of the registers
      # nr     : sequence number when there are multiple instances of a peripheral
      # list   : list of the registers that are part of this peripheral
      def __init__( self, 
         Name, 
         Record, 
         Text, 
         Base, 
         Nr    = None, 
         List  = []
      ):
         self.Name   = Name
         self.Record = Record,
         self.Text   = Text
         self.Base   = Base
         self.List   = List
         self.Nr     = Nr
      
         
      # pad Prefix with the peripheral's sequence number (if none, return '')
      def Nr_Text( self, Prefix = "" ):
         if self.Nr == None:
            return ""
         else:
            return Prefix + str( self.Nr )
   
      # return the name + sequence number (if any)
      def Full_Name( self ):
         return self.Name + self.Nr_Text()
   
      def Define( self, Text, Name, Value ):
         Text.Add( 
            RPad( '#define ' + Name, 32 ) + 
            ' ' + 
            Hex8( Value ))
   
      # return the assembler header for the peripheral      
      def Asm_Text( self ):
         R = Lines()
   
         # comment
         R.Add( "/* " + self.Text + self.Nr_Text( Prefix = " " ) + " */" )
   
         # declare the peripheral name to be its base address
         self.Define( R, self.Full_Name(), self.Base )
   
         # for each register, declare its offset
         for Register in self.List:
            self.Define( 
               R, 
               self.Full_Name() + Register.Name + "_offset", 
               Register.Offset )
   
         # for each register, declare its combined name to be its absolute address
         for Register in self.List:
            if Register.Name != "":
               self.Define( 
                  R, 
                  self.Full_Name() + Register.Name, 
                  self.Base + Register.Offset )
   
         R.Add( "" )
         return R
   
      # return the C header for the peripheral
      def C_Text( self ):
         R = Lines()
   
         # comment
         R.Add( "/* " + self.Text + self.Nr_Text( Prefix = " " ) + " */" )
   
         # declare the structure type
         if(( self.Nr == None ) or ( self.Nr == 0 )):
            R.Add( "typedef struct {" )
            Offset = 0;
            Last_Name = ''
            for Register in self.List:
               N = Register.Offset - Offset
               Name = Register.Name;
               if Name == '':
                  Name = 'X'
               if Name[ 0 ] in "01234567890":
                  Name = '_' + Name;
               if N == -4:
                  R.Add( "   /*overlap: unsigned int %s;*/ " % Name )
                  R.Add( "   #define %s %s" % ( Name, Last_Name ))
               else:
                  if N != 0:
                     R.Add( "   unsigned int anon%d[%d];" % ( Offset, N / 4 ))
                  R.Add( "   unsigned int %s; " % Name )
               Offset = Register.Offset + 4
               Last_Name = Name
            R.Add( "} %s_struct;" % self.Record )
            R.Add( 
                ( "typedef volatile %s_struct " % self.Record ) +
                ( "* %s;" % self.Record ))
         R.Add( "" )
   
         # declare a record of the appropriate type 
         # at the peripheral's base address
         R.Add( 
            "#define " + 
            RPad( self.Name + self.Nr_Text(), 20 ) + 
            " " +
            ( "((%s)(" % self.Record ) + 
            Hex8( self.Base ) + "))" )
   
         # declare each register name to be a pointer to its address
         for Register in self.List:
            if Register.Name != "":
               R.Add( 
                  "#define " + 
                  RPad( 
                     self.Name + 
                     self.Nr_Text() + 
                     Register.Name, 20 ) + 
                  " " +
                  "(*(volatile unsigned int *)(" + 
                  Hex8( self.Base + Register.Offset ) + "))" )
   
         R.Add( "" )
         return R
   
         
   #############################################################################
   #
   # get info from a .map file
   #
   #############################################################################
   
   def Int_From( X ):
      if X.startswith( "0x" ):
         return int( X.replace( "0x", "" ), 16 )
      else:
         return int( X )
         
   class Map_Element:
      def __init__( self, Name, File, Region, Start ):
         self.Name = Name
         self.File = File
         self.Start = Start
         self.Region = Region
         self.Size = -1
         self.Next = None
         
      def __str__( self ):
         Extra = ""
         if 1:
            if self.Next != None:
               Extra = "   " + self.Next.Name
            else:
               Extra = "?"
         return "%7d %-40s %-8s %-30s 0x%08X %s" % \
            ( self.Size, self.Name, self.Region, self.File, self.Start, Extra  )
            
Import_Class( Chip_Peripherals, Export = "*" )              
   
class Map_Info:
   "read the map file produced by the linker "
   "and print extrated info."
   
   class Map_Region:
      def __init__( self, Name ):
         self.Name    = Name
         self.Size    = 0
         self.Elements = []
         
      def Line( self ):
         Size = "?"
         if self.Size > -1:
            Size = "0x%6X  = %5d" % ( self.Size, self.Size )
         return( "   %-6s %s" % ( self.Name, Size ))                
         
      def Process( self ):
         self.Elements = sorted( 
            self.Elements, 
            key = lambda X: X.Name
         )   
         Last = None
         for X in self.Elements:
            if Last != None:
               Last.Size = X.Start - Last.Start
               Last.Next = X
            Last = X 
         
      def Elements_Text( self ):
         Result = Lines()
         for Element in self.Elements: 
            if Element.Name != "#":
               Result.Add( str( Element ))
         return Result
         
   def __init__( self, Map_File ):
      Map = Lines( Map_File )
      Items = [ 
         [ "VECT",    "mkt_ln_vectors_rom"  ],
         [ "CODE",    "mkt_ln_text"         ],
         [ "RODATA",  "mkt_ln_rodata"       ],
         [ "RWDATA",  "mkt_ln_data_ram"     ],
         [ "BSS",     "mkt_ln_bss",         ]]
         
      self.Regions = []       
      Active = None   
      File = "?"
      for Line in Map.Lines:
         Split = Line.Text.split()
         for Region in Items:
            if Line.Text.find( Region[ 1 ]+ "_first = ." ) >0:
               Start = Int_From( Split[ 0 ] )
               Active = self.Map_Region( Region[ 0 ] )
            if Line.Text.find( Region[ 1 ] + "_beyond = ." ) >0:
               Beyond = Int_From( Split[ 0 ] )
               if Active != None:
                  Active.Size = Beyond - Start
                  self.Regions.append( Active )
               Active = None
         if Active != None:      
            if( 
               Line.Text.strip().startswith( '0x') 
               and ( len( Split ) == 2 )
            ):
               Active.Elements.append( 
                  Map_Element( Split[ 1 ], File, Active.Name, 
                     Int_From( Split[ 0 ] )))
            if( 
               ( 
                  Line.Text.strip().startswith( '.') 
                  or Line.Text.strip().startswith( 'COMMON') 
                  or Line.Text.strip().startswith( 'vectors') 
               )
               and ( len( Split ) == 4 )
            ):
               File = os.path.basename( Split[ 3 ] )
               Active.Elements.append( 
                  Map_Element( "#", File, Active.Name,
                     Int_From( Split[ 1 ]) + Int_From( Split[ 2 ]))) 
      for Region in self.Regions:
         Region.Process()
                        
   def Regions_Lines( self ):
      Result = Lines()
      for Region in self.Regions:         
         Result.Add( Region.Line())
      return Result
                    
   def Section_Lines( self ):
      Result = Lines()
      for Region in self.Regions:
         Result.Add_Lines( Region.Elements_Text())
      return Result
                    
class Lib_Base( Docs ):
   "This class has the functions that are used by the more specific "
   "classes to emit code, and the functions to retrieve that code."
   
   def __init__( self ):
      Docs.__init__( self )
      self.UpCall_Nesting = 0
      self.Python_Anchors = 0
      
   def Use_Code( self ):
      return self.UpCall_Nesting == 0
      
   def UpCall( self, Function ):
      self.UpCall_Nesting += 1
      Function()      
      self.UpCall_Nesting -= 1
      
   def Clear_All( self ): 
      Include = '#include "%s"\n' % Mkt_Header_H
      self.Text_Documentation = Lines()
      self.Text_Assembler_Header = "" 
      self.Text_C_Header = "" 
      self.Text_CPP_Header = "" 
      self.Text_Assembler = Include
      self.Text_C = Include
      self.Text_CPP = Include
      
   def Set_Configuration( self, Configuration ):
      self.Configuration = Configuration
      self.Build()
      
   def Build( self ):
      self.Clear_All()
      self.UpCall( super( Lib_Base, self ).Build )
      
   def Caller_Context_Line( self, Text ):
      if self.Python_Anchors:
         Frame = inspect.stack()[ 2 ]
         Line = Frame[ 2 ] - Text.count( "\n" )
         return Line
      else:    
         return 0
      
   def Caller_Context( self, Text ):
      if self.Python_Anchors:
         Frame = inspect.stack()[ 2 ]
         File = Frame[ 1 ]
         Line = Frame[ 2 ] - Text.count( "\n" )
         # PSPad does not like the // or \\ ??
         File = "mkt.py"
         return '#line %d "%s"\n' % ( Line, File.replace( "\\", "/" ))
      else:    
         return ""
      
   # add-text functions, used by the specializations
      
   def Documentation( self, Text ):
      Nr = self.Caller_Context_Line( Text )
      Loc = Location( "", Nr )
      # print( "add doc %d[%d]:%s" % ( self.Python_Anchors, Nr, Text ))
      self.Text_Documentation.Add( Text, Loc )
      
   def Assembler_Header( self, Text ):
      self.Text_Assembler_Header += self.Caller_Context( Text )
      self.Text_Assembler_Header += Unique( Text )
      
   def C_Header( self, Text ):
      self.Text_C_Header += self.Caller_Context( Text )
      self.Text_C_Header += Unique( Text )
      
   def CPP_Header( self, Text ):
      self.Text_CPP_Header += self.Caller_Context( Text )
      self.Text_CPP_Header += Unique( Text )
      
   def Assembler( self, Text ):
      if self.Use_Code():
         self.Text_Assembler += self.Caller_Context( Text )
         self.Text_Assembler += Unique( Text )
      
   def C( self, Text ):
      if self.Use_Code():
         self.Text_C += self.Caller_Context( Text )
         self.Text_C += Unique( Text )
      
   def CPP( self, Text ):
      if self.Use_Code():
         self.Text_CPP += self.Caller_Context( Text )
         self.Text_CPP += Unique( Text )
      
   def Assembler_And_C_Header( self, Text ):
      Text = Unique( Text )
      self.Text_Assembler_Header += self.Caller_Context( Text )
      self.Text_Assembler_Header += Text
      self.Text_C_Header += self.Caller_Context( Text )
      self.Text_C_Header += Text
      
   # retrieve-text functions, used by Mkt_Library
      
   def Get_Documentation( self, File_Name =  None ):
      return self.Text_Documentation
      
   def Get_Assembler_Header( self, File_Name =  None ):
      return Lines_From_Text( self.Text_Assembler_Header, File_Name )
      
   def Get_C_Header( self, File_Name =  None ):
      return Lines_From_Text( self.Text_C_Header, File_Name )
      
   def Get_CPP_Header( self, File_Name =  None ):
      return Lines_From_Text( self.Text_CPP_Header, File_Name )
      
   def Get_Header( self, File_Name =  None ):
      Text = (
         "\n#ifdef __ASSEMBLER__ \n "
         + self.Text_Assembler_Header 
         + """
         #else
            #ifdef __cplusplus
            extern "C" {
            #endif 
         """ 
         + self.Text_C_Header 
         + """
            #ifdef __cplusplus
            }
            #endif          
         #endif          
         """ 
         + """
            #ifdef __cplusplus
         """
         + self.Text_CPP_Header
         + """
            #endif
         """   
         )
      return Lines_From_Text( Text, File_Name )   
      
   def Get_Assembler( self, File_Name =  None ):
      return Lines_From_Text( self.Text_Assembler, File_Name )
      
   def Get_C( self, File_Name =  None ):
      return Lines_From_Text( self.Text_C, File_Name )
      
   def Get_CPP( self, File_Name =  None ):
      return Lines_From_Text( self.Text_CPP, File_Name )
      
def Start_Output_File( name ):
   F = Lines()
   F.Add( Comment( Fill = "*" ))
   F.Add( Comment( "" ))
   F.Add( Comment( name + " include file" ))
   F.Add( Comment( "" ))
   F.Add( Global.Notice, Filter = Comment )
   F.Add( Comment( "" ))
   F.Add( Comment( Fill = "*" ))
   F.Add( "" )
   return F
   
Chips = []
Chip_Names = []   

class Target( Lib_Base ):
   ##########################################################################
   #
   # Basic target class, contains
   #
   # - Chip initialization:
   #    vectors, init stack, clear BSS, copy DATA, call main.
   #    and any other things that might be needed to start the chip
   # 
   # - Memory section macro's
   # - Fatal error handler
   #
   ##########################################################################
   
   def __init__( self, Name, ROM, RAM, Peripherals ):
      global Chips, Chip_Names
      Lib_Base.__init__( self )
      self.Name = Name
      self.ROM = ROM
      self.RAM = RAM
      self.Peripherals = Peripherals
      self.Regions = [ ROM, RAM ]
      Chips.append( self )
      Chip_Names.append( Name )
      
   # chip header file creation   

   def Combined_Include_File_Make( self, Dir = "" ):
      Name = self.Name.lower() + ".h"
      F = Start_Output_File( Name )
      F.Add( "#ifdef __ASSEMBLER__" )
      F.Add( "" )
      for Peripheral in self.Peripherals:
         F.Add_Lines( Peripheral.Asm_Text() )
      F.Add( "#else" )
      F.Add( "" )
      for Peripheral in self.Peripherals:
         F.Add_Lines( Peripheral.C_Text() )
      F.Add( "#endif" )
      F.Write( os.path.join( Dir, Name ))

   def Make_Chip_Header( self, Directory = "" ):
      #self.Linker_Script_Make( RAM())
      #self.Linker_Script_Make( ROM())
      self.Combined_Include_File_Make( Directory )    
            
   def Build( self ):
      self.Configuration.Rule_Check(  "fast_gpio",      Is_Boolean ) 
      self.Configuration.Rule_Extend( Mkt_GCC,          [ 
         "ArmDevEnv", 
         "CodeScourcery" 
         "PIC32GCC" 
      ])
      self.Configuration.Rule_Extend( Mkt_Chip,         [ self.Name ] )
      self.Configuration.Rule_Extend( Mkt_Memory,       [ Mkt_RAM, Mkt_ROM ] )
      self.Configuration.Rule_Extend( Mkt_Run,          [ 
         Mkt_Insight, 
         Mkt_Lpc21isp,
         Mkt_Ocd_Commander, 
      ] )
      self.Configuration.Rule_Extend( Mkt_Board, List_Of_Boards )
      self.Configuration.Rule_Extend( Mkt_Link, [ 
         Mkt_Simulator, 
         Mkt_Wiggler, 
         Mkt_FTDI2232,
         Mkt_ARM_USB_OCD, 
      ] )
      self.Configuration.Rule_Extend( Mkt_Emulator, List_Of_NDS_Emulators )
      self.Configuration.Rule_Check(  Mkt_Xtal,           Is_Numeric )      
      self.Configuration.Rule_Check(  "cclk",             Is_Numeric )      
      self.Configuration.Rule_Check(  "pclk",             Is_Numeric )      
      self.Configuration.Rule_Check(  Mkt_Port,           Is_String  )      
      self.Configuration.Rule_Check(  Mkt_Baudrate,       Is_Numeric )      
      self.Configuration.Rule_Check(  Mkt_Error_Handling, Is_Boolean )      
      
      self.Configuration.Rule_Check(  Mkt_LEDs_N,       Is_Numeric )      
      self.Configuration.Rule_Check(  Mkt_LEDs_595_HQ,  Is_Numeric )      
      self.Configuration.Rule_Check(  Mkt_LEDs_595_SQ,  Is_Numeric )      
      self.Configuration.Rule_Check(  Mkt_LEDs_595_D,   Is_Numeric )
        
      self.Configuration.Rule_Extend( mkt_clcd_Type,    [ "hd44780" ] )
      self.Configuration.Rule_Check(  mkt_clcd_Lines,   Is_Numeric )
      self.Configuration.Rule_Check(  mkt_clcd_Columns, Is_Numeric )
      self.Configuration.Rule_Check(  mkt_clcd_Jump,    Is_Numeric )
      self.Configuration.Rule_Check(  mkt_clcd_E,       Is_Numeric )
      self.Configuration.Rule_Check(  mkt_clcd_RW,      Is_Numeric )
      self.Configuration.Rule_Check(  mkt_clcd_RS,      Is_Numeric )
      for N in range( 0, 8 ):
         self.Configuration.Rule_Check(  "clcd_d%d" % N,      Is_Numeric )
         
      self.Configuration.Rule_Extend( mkt_keypad_type,  [ Mkt_Keypad_HUV4 ] )
      
      self.Configuration.Rule_Extend( mkt_glcd_type,    [ "ks0108", "t6963" ] )
      self.Configuration.Rule_Check(  mkt_glcd_h,       Is_Numeric )
      self.Configuration.Rule_Check(  mkt_glcd_v,       Is_Numeric )
      self.Configuration.Rule_Check(  mkt_glcd_cs1,     Is_Numeric )
      self.Configuration.Rule_Check(  mkt_glcd_cs2,     Is_Numeric )
      self.Configuration.Rule_Check(  mkt_glcd_di,      Is_Numeric )
      self.Configuration.Rule_Check(  mkt_glcd_rw,      Is_Numeric )
      self.Configuration.Rule_Check(  mkt_glcd_e,       Is_Numeric )
      #self.Configuration.Rule_Check(  "glcd_block_write_fast", Is_Boolean );
      for N in range( 0, 8 ):
         self.Configuration.Rule_Check(  "glcd_d%d" % N,      Is_Numeric )
      
      for N in range( 0, 32 ):    
         self.Configuration.Rule_Check( Mkt_LED_Template % N, Is_Numeric )  
         
      self.Configuration.Export()   
         
      self.UpCall( super( Target, self ).Build )
      self.Init_Vectors()
      self.Init_Stack()
      self.Init_BSS_Clear()
      self.Init_DATA_Copy()
      self.Init_Clock()
      self.Init_Chip_Specific()
      self.Init_Call_Main()
      self.Chip_Extra()
      self.Compiler_Extra()
      self.Error_Handler()
      self.Error_Default_Handler()
      self.Memory_Allocation()
      self.Stack_Allocation()
      self.Coroutines()
      self.Memory_Sections()
      self.Run_From_RAM()
      self.Busy_Wait()
      self.Pin_IO()
      self.LEDs()
      self.Character_LCD()
      self.Keypad()
      self.Print()
      self.Graphic_LCD_Common()
      self.Graphic_LCD_KS0108()
      self.Graphic_LCD_T6963()
      self.UART()
      self.Format()
      self.Mkt_Global_Stuff()
      self.Boards()
      self.Interrupts()
      self.Timers()
      self.Streamio()

   ##########################################################################
   #
   # linker script
   #
   ##########################################################################

   def Get_Linker_Script( self, File_Name =  None ):
      return Lines_From_Text( self.Linker_Script(), File_Name )
      
   def Linker_Script( self ):
      T = """
         /* 
          * linkerscript
          */
         
         OUTPUT_FORMAT(
            "elf32-littlearm", 
            "elf32-bigarm", 
            "elf32-littlearm"
         )
         OUTPUT_ARCH( arm )
         ENTRY( _start )
         
         MEMORY {
            %s
            %s
         }
         
         mkt_ln_ram_beyond = 0x%X;
         
         SECTIONS {
        
            /* vectors: load into flash, but 'as if' at address 0 */
            .vectors : /* AT(0) */ {
               mkt_ln_vectors_rom_first = .;
               /* __vectors_start = . */
               *(vectors)
               . = ALIGN(64);
            } > VECTORS
            /* mkt_vectors_load_addr = LOADADDR(.vectors); */
            mkt_ln_vectors_rom_beyond = .;
                                 
            /* instructions */
            .text :
            {
               mkt_ln_text_first = . ;
         
        . = ALIGN(0x4);
   /* PROVIDE(__ctors_start__ = .); */
   __ctors_start__ = .;
        KEEP (*_mkt__*.o(.ctors))
               KEEP (*(.ctors.crt_i_begin))
               KEEP (*(SORT(.ctors)))
               KEEP (*(.ctors.crt_end_n))

        KEEP (*crtbegin.o(.ctors))
        KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
        KEEP (*(SORT(.ctors.*)))
   SORT(CONSTRUCTORS)
   /* PROVIDE(__ctors_end__ = .);   */
   __ctors_end__ = .;   

        . = ALIGN(4);
        __preinit_array_start = .;
        KEEP (*(.preinit_array))
        KEEP(*(.init))
        . = ALIGN(4);
         __preinit_array_end = .;

        . = ALIGN(4);
        __init_array_start = .;
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array))
        . = ALIGN(4);
        KEEP(*(.fini))
        __init_array_end = .;
        
       . = ALIGN(4);
        __fini_array_start = .;
        KEEP (*(.fini_array))
        KEEP (*(SORT(.fini_array.*)))
        __fini_array_end = .;
        
                *(EXCLUDE_FILE (*text.iwram*) .text)
               *(.text)
               *(.text.*)
               *(.stub)
               *(.stub.*)
               /* .gnu.warning sections are          */
               /*    handled specially by elf32.em.  */
               *(.gnu.warning)
               *(.gnu.linkonce.t*)
               *(.glue_7 .glue_7t)
         
               KEEP (*(.init.crt_i_begin))
               KEEP (*(.init))
               KEEP (*(.init.crt_end_n))
   
               KEEP (*(.fini.crt_i_begin))
               KEEP (*(.fini))
               KEEP (*(.fini.crt_end_n))
                                           
         
               . = ALIGN(4);
            } > READONLY
            mkt_ln_text_beyond = . ;
         
         
            /* read-only data */
            .rodata :
            {
               mkt_ln_rodata_first = . ;

               *(.rodata)
               *all.rodata*(*)
               *(.roda)
               *(.rodata.*)
               *(.gnu.linkonce.r*)

               KEEP (*(.dtors.crt_i_begin))
               KEEP (*(SORT(.dtors)))
               KEEP (*(.dtors.crt_end_n))

               . = ALIGN(4);
            } > READONLY
            mkt_ln_rodata_beyond = . ;
            __ro_end = . ;
                  
            .eh_frame :
            {
                    KEEP (*(.eh_frame))
    
                    . = ALIGN(4);
            } > RAM
     
            .gcc_except_table :
            {
                    *(.gcc_except_table)
    
                    . = ALIGN(4);
            } > READONLY
            
            /* uninitialized data */
            .uninitialized : {
               . = ALIGN(4);
               *(.uninitialized)
               *(.uninitialized.*)
            } > RAM
         
            /* read-write initialised data (DATA) */
            .data : {
               mkt_ln_data_ram_first = .;
               
               *(.data)
               *(.data.*)
               *(.gnu.linkonce.d*)
               CONSTRUCTORS
               
               . = ALIGN(4);
             } > INITIALIZED
             mkt_ln_data_ram_beyond = .;
             mkt_ln_data_rom_first  = LOADADDR( .data );
         
            /* read-write uninitialized reserved space (BSS) */
            .bss ( NOLOAD ): {
               . = ALIGN(4);
               mkt_ln_bss_first = .;
               *(.bss)
               *(.bss.*)
               *(.dynbss)
               *(.gnu.linkonce.b*)
               *(COMMON)
               . = ALIGN(4);
             } > RAM
             mkt_ln_bss_beyond = . ;
         
             /* heap */
             _end = . ;
             __end__ = . ;
             PROVIDE (end = _end);
         
         /*-----------------------------------*/
         
              /* STAB debugging sections */
              .stab                   0 : { *(.stab) }
              .stabstr                0 : { *(.stabstr) }
              .stab.excl              0 : { *(.stab.excl) }
              .stab.exclstr   0 : { *(.stab.exclstr) }
              .stab.index             0 : { *(.stab.index) }
              .stab.indexstr  0 : { *(.stab.indexstr) }
              .comment                0 : { *(.comment) }
      
              /* DWARF debug sections
                 Symbols in the DWARF debugging sections are 
                 relative to the beginning
                 of the section so we begin them at 0. */
      
              /* DWARF 1 */
              .debug                  0 : { *(.debug) }
              .line                   0 : { *(.line) }
      
              /* GNU DWARF 1 extensions */
              .debug_srcinfo  0 : { *(.debug_srcinfo) }
              .debug_sfnames  0 : { *(.debug_sfnames) }
      
              /* DWARF 1.1 and DWARF 2 */
              .debug_aranges  0 : { *(.debug_aranges) }
              .debug_pubnames 0 : { *(.debug_pubnames) }
      
              /* DWARF 2 */
              .debug_info             0 : { *(.debug_info) }
              .debug_abbrev   0 : { *(.debug_abbrev) }
              .debug_line             0 : { *(.debug_line) }
              .debug_frame    0 : { *(.debug_frame) }
              .debug_str              0 : { *(.debug_str) }
              .debug_loc              0 : { *(.debug_loc) }
              .debug_macinfo  0 : { *(.debug_macinfo) }
      
              /* SGI/MIPS DWARF 2 extensions */
              .debug_weaknames        0 : { *(.debug_weaknames) }
              .debug_funcnames        0 : { *(.debug_funcnames) }
              .debug_typenames        0 : { *(.debug_typenames) }
              .debug_varnames         0 : { *(.debug_varnames) }
         }
      """ % (
         str( self.ROM ),
         str( self.RAM ),
         ( self.RAM.Start + self.RAM.Size ),
      )
      if self.Configuration.Must_Get( Mkt_Memory ).Value == Mkt_RAM:
         T = T.replace( "RAM",          "ram" )
         T = T.replace( "READONLY",     "ram" )
         T = T.replace( "INITIALIZED",  "ram" )
         T = T.replace( "VECTORS",      "ram" )
      else:
         T = T.replace( "RAM",          "ram" )
         T = T.replace( "READONLY",     "rom" )
         T = T.replace( "INITIALIZED",  "ram AT > rom" )
         T = T.replace( "VECTORS",      "rom" )
      return T      
      
      
   ##########################################################################
   #
   # Mkt globals
   #
   ##########################################################################
   
   def Mkt_Global_Stuff( self ):
      self.C_Header( """
         #define mkt_version "%s (%s)"
      """ % ( Global.Version, Global.Modified ))      

   ##########################################################################
   #
   # chip specifics
   #
   ##########################################################################
   
   def Code_Directive( self ):
      return ""
   
   def Long_Jump( self, Target ):
      Errors.Panic( "no Long_Jump for %s" % self.Name )      

   ##########################################################################
   #
   # chip initialisation code
   #
   ##########################################################################
   
   def Init_Vectors( self ):
      pass

   def Init_Stack( self ):
      pass

   def Init_BSS_Clear( self ):
         # unsigned int *d = __mkt_bss_first;
         # while( d != __mkt_bss_beyond ) *d++ = 0;
      pass

   def Init_DATA_Copy( self ):
         # unsigned int *d = __mkt_data_first;
         # unsigned int *s = __mkt_data_ROM_first;
         # while( d != __mkt_data_beyond ) *d++ = *s++;
      pass

   def Init_Clock( self ):
      pass

   def Init_Chip_Specific( self ):
      pass

   def Init_Call_Main( self ):
         # (void) main( 0, 0 );
         # mkt_error_handler( mkt_return_from_main );
      pass

   def Chip_Extra( self ):
      pass    
      
   def Compiler_Extra( self ):
      self.C_Header( """
         #ifdef __cplusplus
            #define mkt_c_linking "C"
         #else
            #define mkt_c_linking 
         #endif 

      """ )
      self.CPP( """
         extern "C" void __cxa_pure_virtual( void );
         void __cxa_pure_virtual( void ){}
         extern "C" void __cxa_atexit( void );
         void __cxa_atexit( void ){}
         extern "C" void __dso_handle( void );
         void __dso_handle( void ){}
      """ )

      
   ##########################################################################
   #
   # Streamio
   #
   ##########################################################################
   
   def Streamio( self ):
      self.Documentation( """
         #article streamio C++ formatted output
            
         The library contains a reduced implementation of the C++ ostream.
         The limitations are that it does not handle floating point values,
         and formatting can be specified by manipulators only (not by flags).
         The header for this implementation is included automatically;
         the user must not include the standard stream header(s).

         The library provides one pre-defined ostream: cout. 
         This stream calls the
         #link mkt_print_vector
         to print each character. The default mkt_print_vector discards
         the character, so the user should subsitute a suitable function,
         for instance one that uses a UART.

         class ostream

         This is an abstract class, implementing most of the functionality
         of the standard C++ ostream. A derived concrete class must 
         implement the function void putc( char c ), which is called for
         each character that is to be witten. Optionally it can implement
         the function void flush( void ). The default flush does nothing.
         
         The ostream class implements operator<< for char, char array, 
         bool, int, and long long int, and the manipulators left, right, 
         dec, oct, hex, boolalpha, showbase, showpos, setw, setfill, 
         setbase,flush, endl and ends.
     
         class mkt_ostream_putc

         This class inhertits from ostream. 
         Its constructor requires a single parameter void (*f)(char).
         This function is called for each character that is to be written.

         object cout     

         The cout object is an instantiation of the mkt_ostream_putc 
         class,using the 
         #link mkt_print_vector
         to print each character.

         The use of << and manipulators to do formatted output is 
         documented in many places. The following is only a summary.

         C++ uses the operator<< to 'print' a value to an output stream.
         Different << operators are called, depending on the right-side
         argument. Hence there is no need to mention the type of this 
         argument, as you would do with printf. Each << operator returns
         its left argument, hence the notation can be 'chained'.
         The example below first writes a string, then an integer, and
         finally a (newline) character:

         #code
            cout << "Hello " << 2010 << '\\n';
         #end code

         By default each value is printed in a default format, in as many 
         positions as are needed. This can be changed by 'writing' special
         values, called manipulators. Each manipulator changes a certain 
         aspect of how values are printed, for example:

         #code
            // prints:    value = 4D2
            cout << setw( 20 ) << "value " << '=' << hex << 1234;
         #end code

         manipulator setw( n )

         This manipulator sets the minimum field width of the next non-char 
         value that will be printed to n. 
         This manipulator is special in that it affects the next value only.
         After the printing of that 
         variable the field width is set back to the default of 0.
         
         manipulators left, right

         These manipulators determine whether a a value is printed left 
         or right aligned within its field. The default is to print
         right aligned.

         manipulator setfill( c )

         This manipulator sets the character that is used to align a value
         within its field. The default alignment character is the space.

         manipulators bin, oct, dec, hex, setbase( n )

         These manipulators set the radix (numerical base) that is used to
         print integer values. The default radix is 10. 

         manipulators boolalpha, noboolalpha

         These manipulators determine whether a boolean value is printed 
         as 1 or 0 (noboolalpha) or as "true" or "false" (noboolalpha). 
         The default is noboolalpha.

         manipulators showbase, noshowbase

         These maniplualtors determine whether numerical values are prefixed
         by "0b", "0o", or "0x" to indicate the radix used. Note that this
         is different from the C++ standard, which specifies a "0" prefix
         for octal numbers. When a different radix is used the prefix "0?"
         will be used. The default is noshowbase.

         manipulators endl, ends

         These manipulators insert an end-of-line or an ascii nul character.
         These are actually character constants.

         manipulator flush        

         This manipulator has the same effect as calling the flush() 
         member function.

         The example below illustrates the use of cout.

         #code file examples/cout/cout.cpp
            #configure board       hu_arm_v4

               // cout lives in std
            using namespace std;

               // wrapper function for using UART0
            void uart0_write( char c ){ mkt_uart_char_write( UART0, c ); }

            int main( void ){

                  // use UART0 as cout's  putc
               mkt_uart_init( UART0, mkt_baudrate );
               mkt_print_vector = uart0_write;

                  // print char[], int, char
               cout << "Hello world, the year is " << 2010 << '.' << endl;

                  // show effect of setw, setfill, left, right
               cout << "[" << setw(10) << "hi" << "]" << endl;
               cout << "[" << setw(10) << left << "hi" << "]" << endl;
               cout << setfill( '=' ) << right << setw(10) << "hi" << endl;

                  // show effect of boolalpha
               cout << (bool)true << "," << (bool)false << endl;
               cout << boolalpha << (bool)true << "," << (bool)false << endl;

                  // show effect of radix specifiers and showbase
               cout << bin << 5 << " " << showbase << 5 << noshowbase << endl;
               cout << oct << 9 << " " << showbase << 9 << noshowbase << endl;
               cout << dec << 55 << " " << showbase << 55 << noshowbase << endl;
               cout << hex << 57005 << " " << showbase << 57005 << endl;
               cout << setbase( 5 ) << 194 << endl;

               return 0;
            }
         #end code
     
      """ )

      self.CPP_Header( """
         namespace std {
         
         class ostream {
            public:
               ostream( void ) : 
                  field_width( 0 ), 
                  numerical_radix( 10 ),
                  fill_char( ' ' ), 
                  hex_base( 'A' ),
                  align_right( true ), 
                  show_pos( false ),
                  bool_alpha( false ),
                  show_base( false )
               {}
               virtual void putc( char c ) = 0;
               virtual void flush( void ){}
               ostream & operator<< ( char c ){ putc( c ); return *this; }
               
               int width( void ) const { return field_width; }
               void width( int x ) { field_width = x; }
               
               int base( void ) const { return numerical_radix; }
               void base( int x ) { numerical_radix = x; }
               
               bool showpos( void ) const { return show_pos; }
               void showpos( bool x ) { show_pos = x; }
               
               bool boolalpha( void ) const { return bool_alpha; }
               void boolalpha( bool x ) { bool_alpha = x; }
               
               char fill( void ) const { return fill_char; }
               void fill( char x ){ fill_char = x; }
               
               bool showbase( void ) const { return show_base; }
               void showbase( bool x ){ show_base = x; }
               
               void right( void ){ align_right = true; }      
               void left( void ){ align_right = false; }     
               bool must_align_right( void ){ return align_right; }
               
               void filler( int n );
               const char *prefix( void );
               void digit( char c );
            private:
               int field_width;
               int numerical_radix;
               char fill_char;
               char hex_base;
               bool align_right;
               bool show_pos;
               bool bool_alpha;
               bool show_base;
         };
         
         class setw {
            public:
               setw( int x ) : x( x ){}
               int x;
         };
         
         class setbase {
            public:
               setbase( int x ) : x( x ){}
               int x;
         };
         
         extern const setbase bin, oct, dec, hex;
         
         class _showpos {
            public:
               _showpos( bool x ) : x( x ){}
               bool x;
         };
                 
         extern const _showpos showpos, noshowpos;
         
         class _showbase {
            public:
               _showbase( bool x ) : x( x ){}
               bool x;
         };
                 
         extern const _showbase showbase, noshowbase;
     
         class _boolalpha {
            public:
               _boolalpha( bool x ) : x( x ){}
               bool x;
         };
                 
         extern const _boolalpha boolalpha, noboolalpha;
       
         class setfill {
            public:
               setfill( char x ) : x( x ){}
               char x;
         };
                 
         class _right {
            public: 
               _right( void ){}
         }; 
                 
         extern const _right right;
         
         class _left {
            public: 
               _left( void ){}
         }; 
                 
         extern const _left left;
                  
         class _flush {
            public: 
               _flush( void ){}
         }; 
                 
         extern const _flush flush;
                  
         class mkt_ostream_putc : public ostream {   
            public:
               mkt_ostream_putc( void (*f)(char) ) : char_print( f ){}
               void putc( char c ){ (*char_print)( c ); }
               void use( void (*f)(char) ){ char_print = f; }
            private:
               void (*char_print)(char);
         };
         
         extern mkt_ostream_putc cout;
         
         ostream & operator<< ( ostream & stream, const setw & x );
         ostream & operator<< ( ostream & stream, const setbase & x );
         ostream & operator<< ( ostream & stream, const _showpos & x );
         ostream & operator<< ( ostream & stream, const _boolalpha & x );
         ostream & operator<< ( ostream & stream, const _showbase & x );
         ostream & operator<< ( ostream & stream, const setfill x );
         ostream & operator<< ( ostream & stream, const _right x );
         ostream & operator<< ( ostream & stream, const _left x );
         
         ostream & operator<< ( ostream & stream, bool x );
         ostream & operator<< ( ostream & stream, const char *s );
         ostream & operator<< ( ostream & stream, signed char x );
         ostream & operator<< ( ostream & stream, int x );
         ostream & operator<< ( ostream & stream, long int x );
         ostream & operator<< ( ostream & stream, long long int x );
         ostream & operator<< ( ostream & stream, unsigned char x );
         ostream & operator<< ( ostream & stream, unsigned int x );
         ostream & operator<< ( ostream & stream, unsigned long int x );
         ostream & operator<< ( ostream & stream, unsigned long long int x );

         extern const char endl;
         extern const char ends;
         }
      """ )
      
      self.CPP( """
         namespace std {
         
         const char endl = '\\n';
         const char ends = '\\0';

         void ostream :: digit( char c ){
            if( c > 9 ){
                c += ( hex_base - 10 );
            } else {
               c += '0';
            } 
            putc( c );
         }
         
         void ostream :: filler( int n ){
            while( n-- > 0 ){
               *this << fill_char;
            }
         }
         
         ostream & operator<< ( ostream & stream, const setw & x ){
            stream.width( x.x );
            return stream;
         }
         
         ostream & operator<< ( ostream & stream, const setbase & x ){
            stream.base( x.x );
            return stream;
         }
         
         const setbase bin( 2 );
         const setbase oct( 8 );
         const setbase dec( 10 );
         const setbase hex( 16 );
         
         ostream & operator<< ( ostream & stream, const _showpos & x ){
            stream.showpos( x.x );
            return stream;
         }
         
         const _showpos showpos( true );
         const _showpos noshowpos( false );
         
         ostream & operator<< ( ostream & stream, const _showbase & x ){
            stream.showbase( x.x );
            return stream;
         }
         
         const _showbase showbase( true );
         const _showbase noshowbase( false );
         
         ostream & operator<< ( ostream & stream, const _boolalpha & x ){
            stream.boolalpha( x.x );
            return stream;
         }
         
         const _boolalpha boolalpha( true );
         const _boolalpha noboolalpha( false );
         
         ostream & operator<< ( ostream & stream, const setfill x ){
            stream.fill( x.x );
            return stream;
         }
         
         ostream & operator<< ( ostream & stream, const _right x ){
            stream.right();
            return stream;
         }
         
         const _right right;
         
         ostream & operator<< ( ostream & stream, const _left x ){
            stream.left();
            return stream;
         }
         
         const _left left;
         
         ostream & operator<< ( ostream & stream, const _flush x ){
            stream.flush();
            return stream;
         }
         
         const _flush flush;
         
         int strlen( const char *s ){
            int n = 0;
            while( *s != '\\0' ){
               n++;
               s++;
            }
            return n; 
         }
         
         ostream & operator<< ( ostream & stream, const char *s ){
           if( stream.must_align_right()){
              stream.filler( stream.width() - strlen( s )); 
           }  
            for( const char *p = s; *p != '\\0'; p++ ){
               stream << *p;
            }
           if( ! stream.must_align_right()){
              stream.filler( stream.width() - strlen( s )); 
           }  
            stream.width( 0 );
            return stream;
         }
         
         template< int size > class mkt_ostream_reverse_string : public ostream {
            public: 
              mkt_ostream_reverse_string( void ){ p = size; s[ size ] = '\\0'; }
               void putc( char c ){
                  if( p > 0 ){
                     s[ --p ] = c;
                  }
               }
               const char *result( void ){ return & s[ p ]; }
            private:
               char s[ size + 1 ];   
               int p;
         };
         
         ostream & operator<< ( ostream & stream, bool x ){
            if( stream.boolalpha()){
               if( x ){
                  stream << "true";
               } else {
                  stream << "false";
               }
            } else {
               if( x ){
                  stream << "1";
               } else {
                  stream << "0";
               }
            }
            return stream;   
         }

         const char * ostream :: prefix( void ){
            if( ! show_base ){
               return "";
            } else {
               switch( numerical_radix ){
                  case 2  : return "b0";
                  case 8  : return "o0";
                  case 10 : return "";
                  case 16 : return "x0";
               }
            }
            return "?0";
         }
     
         ostream & operator<< ( ostream & stream, signed char x ){
            mkt_ostream_reverse_string<70> s;
            bool minus = ( x < 0 );
            if( x < 0 ){ x = -x; }
            if( x == 0 ){
               s.digit( 0 );
            }
            while( x > 0 ){
               s.digit( x % stream.base() );
               x = x / stream.base();
            }
            s << stream.prefix();
            if( minus ){
               s.putc( '-' );
            } else if( stream.showpos() ){
               s.putc( '+' );
            }   
            stream << s.result();
            return stream;   
         }
         
         ostream & operator<< ( ostream & stream, int x ){
            mkt_ostream_reverse_string<70> s;
            bool minus = ( x < 0 );
            if( x < 0 ){ x = -x; }
            if( x == 0 ){
               s.digit( 0 );
            }
            while( x > 0 ){
               s.digit( x % stream.base() );
               x = x / stream.base();
            }
            s << stream.prefix();
            if( minus ){
               s.putc( '-' );
            } else if( stream.showpos() ){
               s.putc( '+' );
            }   
            stream << s.result();
            return stream;   
         }
         
         ostream & operator<< ( ostream & stream, unsigned int x ){
            mkt_ostream_reverse_string<70> s;
            if( x == 0 ){
               s.digit( 0 );
            }
            while( x > 0 ){
               s.digit( x % stream.base() );
               x = x / stream.base();
            }
            s << stream.prefix();
            if( stream.showpos() ){
               s.putc( '+' );
            }   
            stream << s.result();
            return stream;   
         }
         
         ostream & operator<< ( ostream & stream, unsigned char x ){
            mkt_ostream_reverse_string<70> s;
            if( x == 0 ){
               s.digit( 0 );
            }
            while( x > 0 ){
               s.digit( x % stream.base() );
               x = x / stream.base();
            }
            s << stream.prefix();
            if( stream.showpos() ){
               s.putc( '+' );
            }   
            stream << s.result();
            return stream;   
         }
         
         ostream & operator<< ( ostream & stream, long int x ){
            mkt_ostream_reverse_string<70> s;
            bool minus = ( x < 0 );
            if( x < 0 ){ x = -x; }
            if( x == 0 ){
               s.digit( 0 );
            }
            while( x > 0 ){
               s.digit( x % stream.base() );
               x = x / stream.base();
            }
            s << stream.prefix();
            if( minus ){
               s.putc( '-' );
            } else if( stream.showpos() ){
               s.putc( '+' );
            }   
            stream << s.result();
            return stream;   
         }
         
         ostream & operator<< ( ostream & stream, unsigned long int x ){
            mkt_ostream_reverse_string<70> s;
            if( x == 0 ){
               s.digit( 0 );
            }
            while( x > 0 ){
               s.digit( x % stream.base() );
               x = x / stream.base();
            }
            s << stream.prefix();
            if( stream.showpos() ){
               s.putc( '+' );
            }   
            stream << s.result();
            return stream;   
         }
         
         ostream & operator<< ( ostream & stream, long long int x ){
            mkt_ostream_reverse_string<70> s;
            bool minus = ( x < 0 );
            if( x < 0 ){ x = -x; }
            if( x == 0 ){
               s.digit( 0 );
            }
            while( x > 0 ){
               s.digit( x % stream.base() );
               x = x / stream.base();
            }
            s << stream.prefix();
            if( minus ){
               s.putc( '-' );
            } else if( stream.showpos() ){
               s.putc( '+' );
            }   
            stream << s.result();
            return stream;   
         }
         ostream & operator<< ( ostream & stream, unsigned long long int x ){
            mkt_ostream_reverse_string<70> s;
            if( x == 0 ){
               s.digit( 0 );
            }
            while( x > 0 ){
               s.digit( x % stream.base() );
               x = x / stream.base();
            }
            s << stream.prefix();
            if( stream.showpos() ){
               s.putc( '+' );
            }   
            stream << s.result();
            return stream;   
         }
         
         mkt_ostream_putc cout( mkt_char_print );
         
         }
      """ )
      
           
   ##########################################################################
   #
   # Fatal error handler
   #
   ##########################################################################

   def Error_Handler( self ):
      self.Documentation( """
         #article fatal-error-handling Fatal error handling
         #index mkt_user_error_vector, mkt_FATAL
         #anchor mkt_fatal_error, mkt_FATAL
            
         The library has a simple fatal error handler.
         This handler is for instance called when an unexpected 
         #link exception-vectors exception
         occurs, or when the application tries to allocates more 
         than the available amount of memory, or tries to use
         a non-existing GPIO pin.
      
         The fatal error handler is called with a single parameter,
         which is meant to indentify the the error. 
         It is up to the caller to provide an appropriate
         identification value for each error.
         The MicroKit library code uses small integer values 
         (less than 1000) to indentify an error.
      
         #interface mkt_fatal_error
            handle a fatal error
            #parameter N unsigned int 
               identifies the error
      
         The mkt_fatal_error code jumps to the address it finds
         in mkt_user_error_vector. By default this vector points back
         to the mkt_fatal_error handler, resulting in a neverending
         loop. 
      
         The macro mkt_fatal( N ) can be used to call the error handler
         with parameter N. This works both in assembler and in C/C++.
      
         The configuration parameter mkt_error_handling can be configured
         as 0 to eliminate all error handling, and remove the associated
         code and variables. 
         This will reduce the size
         of the application, but it is like riding a car without a brake.
      
         #literal
            #configure mkt_error_handling 0
         #end literal 
      
         The mkt_user_error_vectors pointer can be overwritten by
         the application to point to an application-defined error handler.
         Such an error handler could for instance blink a LED to indicate
         that an error ocurred. 
         Another approach could be to reset the chip to restart the
         application, but this has the disadvantage that the exception
         might remain unnoticed.
         Note that within this application-defined error handler it 
         is not safe to assume anything, least of all a valid stack 
         pointer, so writing this handler is not trivial and will 
         probably need to be done in assembler.
      
         When the
         #link insight
         debugger is used a breakpoint will be set on the first
         instruction of the error handler. 
         When this breakpoint is triggered the user can inspect the
         appropriate registers (R0 and LR on an ARM) to find out what 
         the exception was and where it ocurred.
      """ )
   
      self.Assembler_And_C_Header( """
         #define mkt_fatal__unhandled_undefined_instruction  #UNIQUE_ERROR
         #define mkt_fatal__unhandled_software_interrupt     #UNIQUE_ERROR
         #define mkt_fatal__unhandled_prefetch_abort         #UNIQUE_ERROR
         #define mkt_fatal__unhandled_data_abort             #UNIQUE_ERROR
         #define mkt_fatal__unhandled_reserved               #UNIQUE_ERROR
         #define mkt_fatal__unhandled_IRQ                    #UNIQUE_ERROR
         #define mkt_fatal__unhandled_FIQ                    #UNIQUE_ERROR
         #define mkt_fatal__memory_allocation_failure        #UNIQUE_ERROR
         #define mkt_fatal__return_from_main                 #UNIQUE_ERROR
         #define mkt_fatal__invalid_pin_number               #UNIQUE_ERROR
         #define mkt_fatal__out_of_interrupt_slots           #UNIQUE_ERROR
      
         //==================================================================
         //
         // default fatal error handler
         //
         // The default mkt_user_error_vector just jumps back to
         // mkt_fatal_error because there is nothing more usefull to do.
         // You can have the mkt_user_error_handler point to a routine 
         // of your choice, but don't assume too much in that routine 
         // (state of peripherals, processor state, availability of a 
         // stack, etc.).
         //
         // TIP: Set a breakpoint on mkt_fatal_error to identify 
         // fatal errors.
         // When it hits, examine R0 to find the cause.
         // The Insight debugger by default sets a breakpoint at 'exit',
         // hence that label is defined equal to mkt_fatal_error. 
         //
         //==================================================================
      """ )
      
      self.Assembler_Header( """
         #if mkt_error_handling == 0 
            // suppress all error handling code
            .macro mkt_fatal, NN 
               // no error handling code
            .endm            
         #endif
      """ )

      self.C_Header( """
         #if mkt_error_handling == 0 
            // suppress all error handling code
            #define mkt_fatal_error( x )
            #define mkt_fatal( x )      
         #else
            void mkt_fatal_error( int x );
            // void /* "C" */ mkt_fatal_error( int x );
            #define mkt_fatal( NN ) mkt_fatal_error( NN );
            // user error pointer!               
         #endif
      """ )
      
      
   ##########################################################################
   #
   # A default fatal error handler
   #
   ##########################################################################

   def Error_Default_Handler( self ):
      self.C_Header( """
         #if mkt_error_handling != 0
            extern unsigned int mkt_error;
            void mkt_error_handler( unsigned int error );
         #endif
      """ )
      
      self.C( """
         #if mkt_error_handling != 0
            unsigned int mkt_error;
            void mkt_error_handler( unsigned int error ){
               mkt_error = error;
               for(;;);
            }
         #endif
      """ )      
      
      self.C_Header( """
         #if mkt_error_handling != 0
            void mkt_default_error_handler( unsigned int error );
         #endif
      """ )
      
      self.C( """
         #if mkt_error_handling != 0
         
            #ifdef UART0
               void mkt_uart0_send( char c ){
                  mkt_uart_char_write( UART0, c );
               }
            #endif
            
            void mkt_default_error_handler( unsigned int error ){
            
               #ifdef UART0
                  mkt_uart_init( UART0, mkt_baudrate );
                  mkt_print_vector = mkt_uart0_send;
                  mkt_string_print( "\\n==== FATAL ERROR ==== : 0d" );
                  mkt_decimal_print( error );
               #endif
               
               #ifdef mkt_clcd_type                  
                  mkt_print_vector = mkt_clcd_char_write;
                  mkt_string_print( "\\vE : " );
                  mkt_decimal_print( error );
               #endif
               
               for(;;){
                  #ifdef mkt_leds_n
                     mkt_leds_write( 0x0F );
                     mkt_busy_wait_us( 200 * 1000 );
                     mkt_leds_write( 0xF0 );
                     mkt_busy_wait_us( 200 * 1000 );      
                 #endif
              }                  
            }
         #endif
      """ )            

      
   ##########################################################################
   #
   # Memory allocation (no deallocation)
   #
   ##########################################################################
   
   def Memory_Allocation( self ):
      self.Documentation( """
         #article memory-allocation Memory Allocation
            
         Memory can be alloacted, but not deallocated. 
         This fits applications that need to allocate memory at startup,
         but can not allocate this memory statically.
      
         #interface mkt_memory_allocate
            allocate a block of memory, return 0 on failure
            #parameter N unsigned int 
               the amount of memory to be allocated (in bytes)
            #result A void *
               the address of (the first byte of) the allocated memory block
   
         #interface mkt_memory_must_allocate
            allocate a block of memory, return 0 on failure
            #parameter N unsigned int 
               the amount of memory to be allocated (in bytes)
            #result A void *
               the address of (the first byte of) the allocated memory block

         The routines mkt_memory_allocate and mkt_memory_must_allocate both
         try to allocate a block of memory, of the size (in bytes) indicated 
         by the parameter. They return the address of (the first byte of) the
         allocated block. 
         When a block of the requested size can not be allocated
         mkt_memory_allocate will return 0, mkt_memory_must_allocate will
         call 
         #link mkt_fatal.

         #interface mkt_memory_free
            return the amount f memory still available 
            #result N unsigned int
               the amount of memory (in bytes) available for allocation

         mkt_memory_free returns the amount of memory (in bytes) available
         for alocation.
         
         For C++ a global operator new is declared that 
         will call mkt_memory_must_allocate.
         This operator is a weak declaration, so you can override
         it in your application.
      """ )
   
      self.C_Header( """
         void * mkt_memory_allocate( int n );
         void * mkt_memory_must_allocate( int n );
         int mkt_memory_free( void );
      """ )
      
      self.C( """      
         // these are labels provided by the linker
         // use the adresses, not the content!
         extern unsigned char mkt_ln_bss_beyond;
         extern unsigned char mkt_ln_ram_beyond;

         // provided by the asm part
         // (would be zero'ed when provided by C)
         extern unsigned char * _mkt_first_free;
         
         void * mkt_memory_allocate( int n ){
            unsigned char *temp;
            
            // round up to nearest multiple of 8
            n = ( n + 7 ) & ~ 0x7;
            
            // allocate 
            temp = _mkt_first_free;
            _mkt_first_free += n;
            
            // succes?
            if( _mkt_first_free > & mkt_ln_ram_beyond ){
            
               // undo allocation
               _mkt_first_free -= n;
               
               // report failure
               return 0;
            }
            
            // reprort succes
            return temp;           
         }
         
         void * mkt_memory_must_allocate( int n ){
            void * temp = mkt_memory_allocate( n );
            if( temp == 0 ){
               mkt_fatal( mkt_fatal__memory_allocation_failure );               
            }
            return temp;
         }

         int mkt_memory_free( void ){
            return &mkt_ln_ram_beyond - _mkt_first_free;
         }
         """ )            
         
      self.CPP_Header( """
         typedef unsigned long int new_arg_type; // should be size_t
         void * operator new( new_arg_type n );
      """ )
      
      self.CPP( """      
         // allow overriding in the application
         void * operator new( new_arg_type n )
            __attribute__ ((weak));
            
         void * operator new( new_arg_type n ){
            return mkt_memory_must_allocate( n );
         }         
      """ )


   ##########################################################################
   #
   # Stack allocation (no deallocation)
   #
   ##########################################################################

   def Stack_Allocation( self ):
      self.Documentation( """
         #article stacks Stacks
            
         A stack of a specified size can be allocated (but not deallocated).
      
         #interface mkt_stack_allocate
            allocate a stack, return 0 on failure
            #parameter size unsigned int 
               the size of the stack to be allocated (in bytes)
            #result S mkt_stack *
               the address representing the stack
   
        #interface mkt_stack_must_allocate
            allocate a block of memory, return 0 on failure
            #parameter size unsigned int 
                the size of the stack to be allocated (in bytes)
            #result S mkt_stack *
                the address representing the stack

         The routines mkt_stack_allocate and mkt_stack_must_allocate both
         try to allocate a stack of the size (in bytes) indicated 
         by the parameter. They return an address tha represents the stack.
         allocated block. 
         When a stack of the requested size can not be allocated
         mkt_stack_allocate will return 0, mkt_stack_must_allocate will
         call 
         #link mkt_fatal.

         #interface mkt_stack_size
            get the size of a stack
            #parameter N mkt_stack * 
               pointer to a stack that was previously allocated
            #result N unsigned int
               the size of the stack

        #interface mkt_stack_used
            get the number of bytes in a stack that were used
            #parameter N mkt_stack * 
               pointer to a stack that was previously allocated
            #result N unsigned int
               the number f bytes that were used

        #interface mkt_stack_unused
            get the number of bytes in a stack that were never used
            #parameter N mkt_stack * 
               pointer to a stack that was previously allocated
            #result N unsigned int
               the number f bytes that were never used
       
         In a stack the original size of the stack is stored, and the stack
         is filled with data. This makes it possible to get both
         the original size of a stack, and the number of bytes in the stack
         that were used or never used. This makes is possible to
         evaluate whether the size of a stack is reasonable.
      """ )

      self.C_Header( """
         typedef struct { } mkt_stack;
         mkt_stack * mkt_stack_allocate( int n );
         mkt_stack * mkt_stack_must_allocate( int n );
         int mkt_stack_size( mkt_stack * stack );
         int mkt_stack_unused( mkt_stack * stack );
         int mkt_stack_used( mkt_stack * stack );
         int mkt_stack_pointer( void );
         int mkt_stack_root( mkt_stack * stack );
         int mkt_stack_top( mkt_stack * stack );
      """ )
      
      self.C( """         
         mkt_stack * mkt_stack_allocate( int n ){
            int i;
            
            // round up to nearest multiple of 4
            n = ( n + 3 ) & ~ 0x03;
            
            // one word extra to store the size
            unsigned int *p = (unsigned int *) mkt_memory_allocate( n + 4 );
            
            if( p == 0 ){
               return 0;
            }
            
            // store size
            p[ n / 4 ] = n;
            
            // fill with 'magic' numbers
            for( i = 0; i < n / 4; i++ ){
               p[ i ] = i;
            }
            
            // a stack 'is' the 'size' entry
            unsigned int *x = p + ( n / 4 );
            return (mkt_stack *) x;
         }         
         
         mkt_stack * mkt_stack_must_allocate( int n ){
            mkt_stack * temp = (mkt_stack *) mkt_stack_allocate( n );
            if( temp == 0 ){
               mkt_fatal( mkt_fatal__memory_allocation_failure );               
            }
            return temp;         
         }
         
         int mkt_stack_size( mkt_stack * stack ){
            int *p = (int *) stack;
            return *( p );
         }

         int mkt_stack_unused( mkt_stack * stack ){
            int *p = (int *) stack;
            int intsize = *( p ) / 4;
            int n;
            p -= intsize;
            for( n = 0; n < intsize; n++ ){
               if( p[ n ] != n ){
                  return 4 * n;
               }
            }
            return 4 * intsize;
         }
         
         int mkt_stack_used( mkt_stack * stack ){
            return mkt_stack_size( stack ) - mkt_stack_unused( stack );
         }
         
         int mkt_stack_root( mkt_stack * stack ){
            return ((int) stack ) - (4 + * (int*) stack );
         }
         
         int mkt_stack_top( mkt_stack * stack ){
            return (int) stack;
         }
         
      """ )            
       
      self.Assembler( """
         mkt_subroutine mkt_stack_pointer            
            mov r0, sp
            # mov r0, #15
            mov pc, lr
      """ )


   ##########################################################################
   #
   # Coroutines
   #
   ##########################################################################

   def Coroutines( self ):
      self.Documentation( """
         #article coroutines Coroutines
            
         #interface mkt_coroutine_create
            create a coroutine
            #parameter f (void *)(void)
               a function (no parameters, no return) 
               that is the body of the coroutine
            #parameter n unsigned int
               the size of the stack to be allocated for the
               execution fo the coroutine
            #result co mkt_coroutine *
               the size of the stack to be allocated for the
               execution fo the coroutine

         A coroutine can be created. 
         This requires a routine or function that contains the 
         code of the coroutine (the body), and a size for the stack. 
         The result is a pointer to an (allocated) 
         coroutine structure.
         When the coroutine structure or the stack can not be allocated
         this routine will return 0.

         The similar routine mkt_coroutine_must_create will call
         #link mkt_fatal
         when the coroutine structure or the stack 
         can not be allocated.

         #interface mkt_coroutine_resume
            resumes execution of a coroutine
            #parameter co mkt_coroutine *
               pointer to the coroutine to be resumed

         mkt_coroutine_resumes resumes execution of the passed coroutine.
         Execution of the current coroutine is suspended untill it
         is resumed by an mkt_coroutine_resume call.

         The main can be resumed by calling 
         #code
         mkt_coroutine_resume( mkt_coroutine_main );
         #end code 
         
         When the subroutine or function that is the body of a coroutine
         returns 
         #link mkt_fatal
         is called (just like when the main() returns).

         For C++ a simple coroutine class is available.
         #code
            class mkt_coroutine_class {
               public:
                  mkt_coroutine_class( 
                     void(*m)(void),
                     int n
                  ){
                     data = mkt_coroutine_must_create( m, n );
                  }
                  
                  void resume( void ){
                     mkt_coroutine_resume( data );    
                  }
                  
                  mkt_stack * stack( void ){
                     return data->stack;
                  }      
            
               private:
                  mkt_coroutine * data;
            };
         #end code
      """ )

      self.C_Header( """

         typedef struct {
            mkt_stack     * stack;
            unsigned int  * _sp;
         } mkt_coroutine;
         
         extern mkt_coroutine mkt_coroutine_main_struct;
         #define mkt_coroutine_main ( & mkt_coroutine_main_struct )
         extern mkt_coroutine *mkt_coroutine_running;
         
         mkt_coroutine * mkt_coroutine_create( 
            void(*m)(void),
            int n
        );
         
         mkt_coroutine * mkt_coroutine_must_create( 
            void(*m)(void),
            int n
        );
         
         void mkt_coroutine_resume( 
            mkt_coroutine *p 
         );
         
      """ )
      
      self.C( """         
         mkt_coroutine mkt_coroutine_main_struct = { 0, 0 };
         mkt_coroutine *mkt_coroutine_running = mkt_coroutine_main;
         extern mkt_c_linking void mkt_return_from_coroutine( void );

         extern mkt_c_linking void mkt_coroutine_switch_context_to( 
            unsigned int ** store_sp, 
            unsigned * new_sp 
         );
                  
         mkt_coroutine * mkt_coroutine_create( 
            void(*m)(void),
            int n
         ){
            mkt_coroutine *p = (mkt_coroutine *) 
               mkt_memory_allocate( sizeof( mkt_coroutine ));
            if( p == 0 ){ return 0; }

            p->stack = mkt_stack_allocate( n );
            if( p->stack == 0 ){ return 0; }

            ((unsigned int * )p->stack)[ -1 ] = ( unsigned int ) m;
            
            // if I told you why 12 I'd have to kill you ;)
            p->_sp = ((unsigned int * )p->stack) - 12;

            return p;
         }
         
         mkt_coroutine * mkt_coroutine_must_create( 
            void(*m)(void),
            int n
         ){
            mkt_coroutine *p = (mkt_coroutine *) 
               mkt_memory_must_allocate( sizeof( mkt_coroutine ));

            p->stack = mkt_stack_must_allocate( n );

            ((unsigned int * )p->stack)[ -1 ] = ( unsigned int ) m;
            
            // if I told you why 12 I'd have to kill you ;)
            p->_sp = ((unsigned int * )p->stack) - 12;

            return p;
         }
         
         void mkt_coroutine_resume( 
            mkt_coroutine *p 
         ){
            mkt_coroutine *old = mkt_coroutine_running;
            mkt_coroutine_running = p;
            mkt_coroutine_switch_context_to( &old->_sp, p->_sp );
         }          
         
      """ )            

      self.Assembler( """         
      
         // void mkt_coroutine_switch_context_to( 
         //    void ** store_sp, 
         //    void * new_sp 
         // );
         
            mkt_subroutine mkt_coroutine_switch_context_to
            
            // save old C context
            stmfd   sp!, { r2-r12, lr }
               
            // remember current (old) sp
            str sp, [ r0 ]
            
            // set new sp
            mov sp, r1
            
            // this is for the coroutine's 'main' only
            ldr lr, =mkt_return_from_coroutine
                  
            // install new C context
            ldmfd   sp!, { r2-r12, pc }
                  
      """ )            
      
      self.CPP_Header( """
         class mkt_coroutine_class {
            public:
               mkt_coroutine_class( 
                  void(*m)(void),
                  int n
               ){
                  data = mkt_coroutine_must_create( m, n );
               }
               
               void resume( void ){
                  mkt_coroutine_resume( data );    
               }
               
               mkt_stack * stack( void ){
                  return data->stack;
               }      
         
            private:
               mkt_coroutine * data;
         };

      """ )


   ##########################################################################
   #
   # memory sections
   #
   ##########################################################################

   def Memory_Sections( self ):
      self.Documentation( """
         #article memory-sections Memory sections
         #index sections, RAM, ROM, FLASH
      
         Assembler code that wants to be able to run from ROM must specify 
         how the code and data is to be distributed over RAM and ROM. 
         This section explains how this is done. 
         When you write your code in C or C++ the compiler takes care of 
         placing code and data in the correct segments.
         
         An embedded system uses ROM and RAM. When the application is run 
         from RAM the picture is simple: all elements of the application 
         reside in RAM. When the application runs from ROM the picture is 
         more complicated. RAM is more expensive for the chips manufacturer 
         than ROM, so most chips contain much more ROM than RAM. 
         Hence the use of RAM must be minimized. 
         Code and read-only data (the text segment) generally resides 
         in ROM only. Data that needs no initialization (stack, heap) 
         and data that is initialized to zero (the bss segment) resides in 
         RAM. Data that has a specific initialization value, 
         yet needs to be writeable (the data segment), must be treated 
         special: it resides in RAM, but an image of it is kept in ROM. 
         Before the application itself starts, this image is copied to RAM, 
         and the zero-initialised data (bss segment) is cleared. 
         """ )
      Dummy = ( """

         This is done by the 
         #link ea-startup
         startup
         code. 
         (The copying is done only when the 
         #link mkt_memory
         is specified as 
         #link mkt_rom
         because it is not needed for 
         #link mkt_ram). 
         
         When you write your code in C or C++ the compiler takes care 
         of placing code and data in the correct segments. 
         When you use assembler you must manage this yourself. 
         The library provides macros to make this a bit easier 
         (but you must still do the thinking):
         #list
         
            The macro 
            #link mkt_code
            is used before code (instructions, code segment). 
         
            The macro 
            #link mkt_data
            is used before read-write data that needs has 
            a specific initialization value (bss segment). 
         
            The macro 
            #link mkt_bss
            is used before zero-initialised data (data segment). 
         
            The macro 
            #link mkt_rodata
            is used before read-only data (this could 
            equally well be put in the text segment using the 
            #link mkt_code 
            macro, but a separate  macro explains the 
            intention of the programmer more clearly).
         
            A piece of assembler code will often be a subroutine. 
            The macro 
            #link mkt_subroutine
            can be useful for this situation because it 
            combines the effect of the 
            #link mkt_code
            macro with the declaration of the (externally accessible) 
            subroutine label, and it places each subroutine in a separate
            section, which helps to reduce the size of the application.
         
         #end list
         """ )
         
      self.Assembler_Header( """   
            // start of a section of assembler code that can be placed in ROM
            .macro mkt_code
               .text
               .align
               %s
            .endm   
         """ % self.Code_Directive() )
            
      self.Documentation( """
         #article memory-sections
         In most cases assembler code will be a subroutine, 
         for which the macro
         #link mkt_subroutine
         will be more convenient, because it handles the label,
         and puts each subroutine in a separate section, which
         makes it possible for the linker to eliminate unused
         subroutines.
      
         #article memory-sections 
         #header mkt_code
         
         The mkt_code assembler macro starts an assembler code section. 
         This macro generally expands to:
         
         #code
            .text
            .align
         #end code
         
         Use this macro before a section that contains assembler code
         which can be placed in ROM, for instance:
         
         #code
               mkt_code
            multiply_by_two: 
               add r0, r0, r0
               mov pc, lr
         #end code  
         """ )
            
      self.Assembler_Header( """
            // start of a section for read/write, 
            // explicitly initialised data
            .macro mkt_data
               .data
               .align
            .endm
            
            .macro mkt_uninitialized
               .section .uninitialized
               .align
            .endm                  
         """ )
      
      self.Documentation( """
         #article memory-sections
         #header mkt_data
         
         The mkt_data assembler macro starts an initialised read-write 
         data section. This macro expands to
         
         #code
            .data
            .align
         #end code
         
         Use this macro before a data section that has explicit (non-zero)
         initialisations, for instance:      
         #code
            mkt_data
            initial_message: .ASCIZ "Can be changed by the application."
         #end code
         
         This macro should be used rarely, most data either needs no
         explicit initialisation (use 
         #link mkt_bss) 
         or is read-only 
         (use 
         #link mkt_rodata). 
         When run from ROM a DATA section occupies
         both ROM and RAM, and when running form RAM it must be loaded
         at the start of each session. A 
         #link mkt_bss
         section occupies
         only RAM, and need not be loaded (it is initialised to zero by
         a loop in the 
         //  #link ea-startup
         startup code). 
         A 
         #link mkt_rodata
         section occupies
         only ROM. 
         Most microcontroller chips have much more ROM than RAM, 
         so it is important to place as much as possible in ROM.
         """ )
         
      self.Assembler_Header( """
            // start of a section for read/write, 
            // 0-initialised data
            .macro mkt_bss
               .bss
               .align
            .endm
         """ )
      
      self.Documentation( """
         #article memory-sections
         #header mkt_bss
         
         The mkt_bss assembler macro starts a 0-initialised read-write 
         data section. This macro expands to
         
         #code
            .bss
            .align
         #end code
         
         Use this macro before a data section that either needs no 
         initialisation, or must be initialised to zero, for instance:
         #code
                              mkt_bss
            buffer:           .skip 256
            characters_sent:  .word 0
         #end code
         
         mkt_bss sections occupy only RAM (no ROM) and do not add to the
         'startup' time when you are debugging: BSS sections are 
         automatically initialised to zero by a loop in the 
         //  #link ea-startup.
         startup code.
         """ ) 
      
      self.Assembler_Header( """
            // start of a section for read-only, initialised data
            .macro mkt_rodata
               .text
               .align
            .endm
         """ )
      
      self.Documentation( """
         #article memory-sections
         #header mkt_rodata
         
         The mkt_rodata assembler macro starts a read-only data section.
         This macro expands to
         
         #code
            .text
            .align
         #end code
         
         Use this macro before a data section that will only be read
         (never written), for instance:
         #code
                              mkt_rodata
            Message_List:     .word Message_One
                              .word Message_Two
                              .word 0
            Message_One:      .asciz "Hello world!"
            Message_Two:      .asciz "It is a nice day."
         #end code
         
         When running from ROM mkt_rodata sections occupy only ROM (no RAM).
         When you are debbuging mkt_rodata sections are downloaded, so they add
         to the 'startup' time. 
         
         Note that mkt_rodata has almost the same expansion as 
         #link mkt_code, 
         but using a separate macro states the intent of the programmer 
         more clearly.
         """ )
      
      self.Assembler_Header( """
            // this used to give problems with Insight, I have no idea why.
            // but with the new gcc and gdb these seem to be solved
            .macro mkt_code_separate_section, Name
                  .text
                  .section .text.\\Name,"ax"
                  .arm
                  .align
            .endm   
         
            // start of a subroutine:
            // the label is put in front, and the label is made global 
            .macro mkt_subroutine, label
                  mkt_code_separate_section \label
                  .global \label
               \label:      
            .endm
         """ )
         
      self.Documentation( """
         #article memory-sections 
         #header mkt_subroutine
         
         mkt_subroutine is an assembler macro that can be used 
         to start a section that contains a subroutine.
         This macro has one parameter, the label (name)
         of the subroutine. It expands to
         
               .section .text.\label
         #code
               mkt_code
               .global \label
            \label:      
         #end code
         
         The .section line causes each subroutine to be placed in a
         unique section. When the linker needs a label, it will include
         all of the section that contains that label. Without the .section
         line all subroutines in a source file would be in the same section,
         so they would all be linked into your application when only one
         is used. With the .section line only the subroutines that are
         actually used will be linked, so the size of the application
         is reduced.
         
         Use this macro to start a subroutine that must be visible
         outside the current file, for instance:
      
         #code
            mkt_subroutine multiply_by_two
               add r0, r0, r0
               mov pc, lr
         #end code
         """ )

   ##########################################################################
   #
   # assembler macro's for running from RAM
   #
   ##########################################################################

   def Run_From_RAM( self ):
      self.Documentation( """
         #article run-from-RAM RAM subroutines in a ROM application
         #index RAM
         
         Some chips can run at full speed when instructions are fetched 
         from RAM, but not when instructions are fetched from ROM. 
         The chips often provide an option to prefetch and/or buffer reads 
         from ROM to speedup the average execution speed from ROM, but this 
         reduces the instruction-by-instruction predictability of the 
         execution speed. 
         
         When a piece of code must be run at full and/or predictable 
         speed it should be executed from RAM. This can be achieved by 
         putting the instructions in the data segment (which is copied to 
         RAM before the application starts). The C and C++ compilers can
         place a function in RAM and arrange for the correct calling
         sequence for such a function, but when you code in assembler
         you will have to do some work yourself. This section
         documents macro's that can help with this.
         
         The macro 
         #link mkt_code_in_ram
         can be used to place code in RAM. The 
         #link mkt_data
         macro could also be used to place code in RAM
         (the effect is the same), but use of the mkt_code_in_ram
         macro states the programmers intent more clearly.
          
         The default instruction used by most chips to jump to a subroutine 
         has (only) a limited field to identify the address to jump to. 
         An ARM chip for instance, uses the BL instruction, which has
         a 24-bit signed offset. 
         When the calling code is in ROM and the entry point (label) 
         of the code would be in RAM this could cause a problem because the 
         ROM and RAM memory areas can be further apart than the offset 
         allowed by the jump-to-subroutine instruction. 
         Hence the call entry point for a subroutine must be in ROM 
         (assuming the application is running from ROM), 
         even when the body of the code is in RAM. 
         The macro 
         #link mkt_subroutine_in_ram 
         places the entry point 
         of a subroutine in ROM but the body in RAM. This macro uses the 
         #link mkt_jump_to_ram 
         macro.
      
         Note that code executed from RAM can not safely use the default
         call-subroutine instruction to call code in ROM. 
         This will most likely not be needed anyway, 
         because it would defeat the main purpose of execution from RAM: 
         full and predictable execution speed. But it is not unlikely that 
         before the critical (RAM located) code is entered some preparations 
         must be made, and these preparations could require calling other 
         (ROM-based) code. Another argument to switch to RAM later in a 
         subroutine (instead of at the entry point) is that RAM is a scarce 
         resource and its use should be minimized. The 
         #link mkt_jump_to_ram 
         macro switches from ROM-located code to 
         RAM-located code within a subroutine:
         
         (snip?) == edit from here
      
         #header ARM_IN_ARM
         #anchor ARM_IN_RAM
      
         The macro ARM_IN_RAM can be used to place code in RAM. 
         Running from RAM can be faster and has a more predictable 
         execution time than running from ROM.
        
         This macro only places the code in RAM, the user is responsible for
         passing control to that code. The 
         #link ARM_SWITCH_TO_RAM 
         and
         #link ARM_RAM_SUBROUTINE 
         macros provide a convenient way to to this.
         
         this macro expands to
         #code
            #if mkt_MEMORY == mkt_RAM
               ARM
            #else
               .data
               .arm
               .align
            #endif
         #end code
         
         Note that when the target is specified as RAM there is no need to do 
         anything special, because everything will end up in RAM anyway.
      """ )
      
      self.Assembler_Header( """
            // start of a code part that must be in RAM
            // the user is responsible for jumping to this code!
            .macro mkt_code_in_ram
               #if mkt_memory == mkt_ram
                  mkt_code
               #else
                  mkt_code
                  .data
               #endif
                  .align 4
            .endm
      """ )
         
      self.Documentation( """
         #article run-from-RAM
         #header ARM_RAM_SUBROUTINE
         // #anchor ARM_RAM_SUBROUTINE
      
         The macro ARM_RAM_SUBROUTINE can be used to create a subroutine
         that is located (fully) in RAM, but still has an entry point in ROM
         (assuming the application is run from ROM). It requires two
         one parameters, the first is the name (entry point) of the subroutine
         in ROM, the second is the entry point in RAM (which should not
         be used directly by the application).
         
         When the initial part of the subroutine can be in ROM the 
         #link ARM_SWITCH_TO_RAM 
         macro can be used instead to limit the amount of RAM used. 
         
         The ARM_RAM_SUBROUTINE macro with a FOO and _FOO_in_RAM 
         arguments expands to:
         
         #code
               ARM_SUBROUTINE FOO
               ARM_SWITCH_TO_RAM FOO_in_RAM
         #end code
         
         The 
         #link ARM_SUBROUTINE 
         and 
         #link ARM_SWITCH_TO_RAM 
         macros take care of all the details.
      """ )
         
      self.Assembler_Header( """
            // start of an ARM subroutine that must be in RAM
            // a trampoline is inserted in ROM so the subroutine
            // can be called with a standard BL instruction
            .macro mkt_subroutine_in_ram, label, label_in_ram
               mkt_subroutine \label
               mkt_switch_to_ram \label_in_ram   
            .endm    
      """ )
         
      self.Documentation( """
         #header ARM_SWITCH_TO_RAM
         // #anchor ARM_SWITCH_TO_RAM
         
         The ARM_SWITCH_TO_RAM macro requires one label.
         It inserts a jump to that label, a directive to
         put further code in RAM, and the label. The effect
         is that the code before the macro can be in ROM,
         and the code after it will end up in RAM.
         
         The jump is coded using the ldr (pseudo-) instruction. 
         This is is translated by the assembler to the loading of 
         a full word that is addressed using 
         pc-relative addressing. This makes it possible to load a full 32-bit 
         value, but at the expense of an extra nearby memory location. 
         Next the 
         #link ARM_IN_RAM 
         macro is used to force the subsequent code to RAM,
         and the entry label for this code is declared. It is declared global 
         to make it visible in the linker memory map. Note that just like the 
         ARM_IN_RAM macro, nothing needs to be done when the target is 
         specified as RAM. 
         
         The ARM_SWITCH_TO_RAM macro with a FOO argument expands to:
         
         #code
            #if mkt_memory == mkt_ram
               ldr pc, =\FOO
               ARM_IN_RAM
               .global \FOO
               \FOO:         
            #endif
         
         #end code
            
         The typical use of this macro is shown in this 
         code for a hypothetical MicroKit subroutine: 
      
         #code
               /* toggle an IO pin very fast, R0 == pin number */
            ARM_SUBROUTINE mkt_wiggle
               mov   r3, r0
               
               /* make the pin a GPIO output */
               ldr   r1, =1
               bl    mkt_GPIO_direction
               
               /* get and save the SET register pointer */
               mov   r0, r3
               bl    mkt_GPIO_SET
               mov   r2, r0
      
               /* get and save the CLR register pointer */
               mov   r0, r3
               bl    mkt_GPIO_CLR
               mov   r3, r0
               
               /* create the mask for the pin */
               mov   r0, #0
               mov   r0, r0, shl r3
               
               /* preparation done, now to RAM for speed */
            ARM_SWITCH_TO_RAM mkt__wiggle_in_RAM
            
            loop:   
               str   r0, [r2]
               str   r0, [r3]
               b     loop
            
         #end code     
      
         Note that the entry label for the RAM part has a double 
         underscore after 'EA', and a suffix _in_RAM. 
         This is the convention used by MicroKit library code.
      """ )
         
      self.Assembler_Header( """
            // start of an ARM code part that must be in RAM
            // the label and a jump to that label are inserted
            .macro mkt_switch_to_ram, label
               #if mkt_memory == mkt_rom
                  %s
                  mkt_code_in_ram
                  .section .data.\label
                  .global \label
                  .align 4
                  \label:         
               #endif
            .endm   
      """ % self.Long_Jump( "\label" ) )
      
   ##########################################################################
   #
   # busy waiting
   #
   ##########################################################################
   
   def Busy_Wait( self ):
      self.Documentation( """
         #article busy-waiting Busy waiting
            
         #interface mkt_busy_wait_us
            busy-wait the indicated number of microseconds
            #parameter us unsigned int
               the number of microseconds to wait
               
         The mkt_busy_wait_us routine waits the indicated number 
         of microseconds.
         The actual wait time can be somewhat higher than the 
         requested time, because the call and preparation overhead 
         is not taken into account, and it is assumed the CPU runs 
         uninterrupted and at full speed (no interrupts, 
         no instruction fetch stalls). 
         On some chips code can rull at full speed from RAM
         but not from ROM. 
         In those cases the actual delay loop will be placed in RAM.
         
         This function should be used when the code must wait a certain 
         minimum time, for instance to satisfy the timing requirements of 
         an external chip.
         The library itself uses this function for instance to interface
         to an HD44780 LCD controller. 
         When timing accuracy is important this function should probably 
         not be used, consider using a hardware timer instead.
      
         The argument is an unsigned 32 bit integer, so the maximum wait 
         time is almost 4295 seconds. If you need a longer wait time I 
         guess you can implement it yourself.
         
         Currently
         #anchor mkt_wait_us 
         mkt_wait_us is a synonym for mkt_buys_wait_us. 
         When multitasking is implemented, mkt_wait_us will
         (at its sole descretion) either do a busy wait 
         (as it does now), or ask the multitasker
         to suspend the current task for the indicated time. 
         Hence the use of mkt_wait_us is to be preferred over 
         mkt_busy_wait_us,
         unless you realy realy wants a busy wait.
      """ )
      
      self.C_Header( """
         void /* "C" */ mkt_busy_wait_us( int us ); 
      """ )
      
      self.Assembler_And_C_Header( """
         #define mkt_wait_us mkt_busy_wait_us
      """ )
      
      
   ##########################################################################
   #
   # interrupts
   #
   ##########################################################################
   
   def Interrupts( self ):
      self.Documentation( """
      """ )
      
      self.C_Header( """
         void mkt_vic_int_init( int nr, int slot, void (*isr)(void) );
      """ )            
      
      self.C( """
         void mkt_vic_int_init( int nr, int slot, void (*isr)(void) ){
            VICIntSelect &= ~(1 << nr);          // select IRQ mode 
            (&VICVectCntl0)[ slot ] = 0x20 | nr; // enable interrupt
            (&VICVectAddr0)[ slot ] = (int) isr; // store vector
            VICIntEnable |= 1 << nr   ;          // enable source
            VICVectAddr = 0xFF;
         }
      """ )            

   ##########################################################################
   #
   # timers
   #
   ##########################################################################
   
   def Timers( self ):
      self.Documentation( """
      """ )

      self.C_Header( """
         void mkt_timer_periodic_int_init( TIMER t, int period );
         void mkt_timer_free_running( TIMER t, int tick );
      """ )
      
      self.C( """
         void mkt_timer_periodic_int_init( TIMER t, int period ){
            t->TCR = 0;                      // stop and reset
            t->PR  = 0;                      // prescaler divides by 1
            t->MR0 = ( mkt_pclk / MHz ) 
               * period;                     // max counter value
            t->MCR = (1 << 1) | (1 << 0);    // reset and interrupt
            t->IR  = 0xFF;                   // clear interrupt flags
            t->CTCR = 0;                     // counter mode
            t->TCR = 1;                      // start timer 
         }
         
         void mkt_timer_free_running( TIMER t, int tick ){
            t->TCR = 0;                      // stop and reset
            t->PR  = -1 +
               (( mkt_pclk / MHz ) * tick);  // prescaler
            t->MCR = 0;                      // do nothing
            t->CTCR = 0;                     // counter mode
            t->TCR = 1;                      // start timer 
         }
      """ )
      
           
   ##########################################################################
   #
   # pin I/O
   #
   ##########################################################################
   
   def Pin_IO( self ):
      self.Documentation( """
         #article pinio

         On most 32 bit chips the chip documentation puts the pins
         in groups of 32, like 0.0 .. 0.31 for the first group, 
         1.0 .. 1.31 for the second group, etc.          
         For the library routines the I/O pins are numbered from 0 up to 
         the number of available I/O pins, so the first group would be
         pins 0 .. 31, the secodn would be pins 32 .. 63, etc.
         
         Pins can often be used for more than one purpose, basic I/O being
         one of these purposes. The function
         
            void mkt_pin_configure( int pin, mkt_direction direction )
            
         configures a pin as absic I/O pin, and sets the direction as
         indicated (can be mkt_input or mkt_output).
         
         Once a pin has been configured as basic I/O pin, it can be read
         (if configured for input) or written (if configured for output).
         For writing the value can be specified as parameter, or a 
         
            unsigned char mkt_pin_read( int pin )    
            void mkt_pin_write( int pin, int value )
            void mkt_pin_set( int pin )
            void mkt_pin_clear( int pin )
            
         Is is alose posisble to change the direction of a pin without
         doing a full configuration.
         
            mkt_pin_direction( int pin, mkt_direction direction )
            
         For the mkt_pin_direction, mkt_pin_read, mkt_pin_write, 
         mkt_pin_clear and mkt_pin_set functions a variation 
         (actually a macro)is available 
         that executes much faster, but requires the pin number to be
         a constant:
         
            void mkt_fixed_pin_direction( pin, mkt_direction direction )
            int mkt_fixed_pin_read( pin )    
            void mkt_fixed_pin_write( pin, int value )
            void mkt_fixed_pin_set( pin )
            void mkt_fixed_pin_clear( pin )         

      """ )

      self.Documentation( """
         #article basic-io Basic IO

         The general-purpose IO pins of a microcontroller can be set 
         (made high or low) and read directly by the processor. 
         This is the most basic way to use an IO pin.
         When a more complex protocol is implemented in software
         (the processor is fully responsible for setting the pin
         direction and values, and for the correct timing) 
         this is often referred to as bit-banging. 
         (As opposed to using build-in hardware, like a UART.)
         
         In the library a general-purpose IO pin is identified by a number, 
         counting from 0 up to the number of available pins. 
         The chip documention often refers to the pins in sets of 32 pins,
         like P0_0 .. P0_31 and P1_1 .. P1_31, etc.
         The library indentifies these pins as 0 .. 31 and 32 .. 63.
         
         The pins are often shared between the basic general-purpose
         IO function and one or more hardware peripherals 
         (UARTs, counters, PWM, etc). 
         To use a pin as basic IO pin it must first be configured as such
         (as opposed to for instance PWM output), 
         and be set to the correct direction (input or output). 
         After this has been done the pin can be written 
         (made high or low) or read. 
      
         On most 32-bit microcontroller the I/O part of the chip 
         runs at 3.3V, but the pins are 5V tolerant: when used as input they 
         accept 0..5V. 
         (But do check the datasheet, and take note: 
         applying > 3.3V to any input pin has been reported 
         to degrade the performance of the A/D converter.)
         // check and when used as output you can attach a pull-up resistor 
         // to 5V. 
         
         The library provides a number of services that can be used 
         to manipulate IO pins. 
         The easiest way is to first set the direction, 
         and then write or read the pin, using the functions 
         #link mkt_pin_direction, 
         #link mkt_pin_write 
         and 
         #link mkt_pin_read.
         
         #code
            void mkt_pin_configure( int N, int D );
            void mkt_pin_write( int N, int V );
            unsigned char mkt_pin_read( int N );
         #end code
      
         N is the number of the IO pin. 
         D is the desired direction (allowed values are 
         #link mkt_input mkt_input 
         and 
         #link mkt_output mkt_output). 
         V is the value that must be written to the IO pin,
         conform the C convention for truth values:
         0 for low, any other value for high. 
         Likewise mkt_pin_read_read returns 0 when the pin is low, 
         or a non-zero value when the pin is high. 
         A call to 
         #link mkt_pin_direction both
         configures the pin as basic IO pin,
         and sets the direction to input or output, as specified by D. 
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         
         These very simple code snippets 
         copy pin 0 (input) to pin 1 (output):
      
         #code
            mkt_pin_configure( 0, mkt_input );
            mkt_pin_configure( 1, mkt_output );
            while( 1 ){
               mkt_pin_write( 1, mkt_pin_read( 0 ) );
            }
         #end code
      
         #code
               ldr   R0, =0
               ldr   R1, =mkt_input
               bl    mkt_pin_configure
      
               ldr   R0, =1
               ldr   R1, =mkt_output
               bl    mkt_pin_configure
      
            loop:
               ldr   R0, =0
               bl    mkt_pin_read
      
               mov   R1, R0
               ldr   R1, =1
               bl    mkt_pin_write
            
               b loop
         #end code
      
         //The standard 'place' for the registers that control the GPIO pins is on 
         //the peripheral bus, which is slower than the ARM core. Some ARM chips 
         //have an alternate set of registers that can be used to read and 
         //write to the GPIO pins. 
         //This alternate set is attached tightly to the CPU to 
         //allow one-cycle access. By default this faster set will be used if 
         //it is available. The configuration option 
         //#link mkt_fast_gpio
         //can be 
         //used to force the use of the lower set (for instance to get the 
         //same timing on chips with only the slower option and 
         //chips with both options).
         
         //The function 
         //#link MK_GPIO_connect 
         //can be used to configure a pin to a specific function, 
         //encoded as a 2 bit value.
         //When you use 
         //#link mkt_pin_configure 
         //you do not need this call, because mkt_pin_configure always sets 
         //the pins configuration to GPIO. 
         //
         //#code
         //   void MK_GPIO_connect( int N, int C );
         //#end code
      
      #article basic-io 
         #header mkt_pin_configure
         #index mkt_pin_direction, mkt_input, mkt_output
         #index direction, pin direction, GPIO
         
         #anchor mkt_input, mkt_output
         #interface mkt_pin_configure
            #parameter N unsigned int 
               number of the IO pin
            #parameter D unsigned int
               direction for the pin
            
         This function configures the indicated IO pin as basic IO pin and
         sets the direction as specified by the direction parameter.
         The allowed values for the direction parameter are 
         mkt_input and mkt_output.
         
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.         
      """ )
      
      self.Assembler_And_C_Header( """      
         #define mkt_input   0
         #define mkt_output  1
      """ )
      
      self.C_Header( """      
         void /* "C" */ mkt_pin_configure( int N, int D );
      """ )
               
      self.Documentation( """
         #article basic-io 
         #header mkt_pin_direction
         #index mkt_pin_direction, mkt_input, mkt_output
         #index direction, pin direction, GPIO
         
         #anchor mkt_input, mkt_output
         #interface mkt_pin_direction
            #parameter N unsigned int 
               number of the IO pin
            #parameter D unsigned int
               direction for the pin
            
         This function sets the direction of the indicated IO pin
         as pecified by the direction parameter.
         The allowed values for the direction parameter are 
         mkt_input and mkt_output.
         
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.         
      """ )
      
      self.Assembler_And_C_Header( """      
         #define mkt_input   0
         #define mkt_output  1
      """ )
      
      self.C_Header( """      
         void /* "C" */ mkt_pin_direction( int N, int D );
      """ )
               
      self.Documentation( """      
      #article basic-io 
         #header mkt_pin_write
         
         #interface mkt_pin_write
            #parameter N unsigned int 
               number of the IO pin
            #parameter V unsigned int
               value for the pin
            
         This function sets the value of the indicated IO pin.
         A false (zero) value for V makes the pin low (0), a true
         (non-zero) value makes the pin high (1).
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         The pin must be configure as basic IO pin and as output.
         Function 
         #link mkt_pin_configure
         can be used to do both.
         
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler. 
      """ )
      
      self.C_Header( """      
         void /* "C" */ mkt_pin_write( int N, int V );
      """ )
               
      self.Documentation( """      
      #article basic-io
         #header mkt_pin_read
         
         #interface mkt_pin_read
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int
               value of the pin
            
         This function returns the value of the indicated IO pin.
         If the pin is low (0) a false (0) value is returned, 
         if the pin is high (1) a true
         (non-zero) value is returned.
         The pin must be configure as basic IO pin and as input.
         The function 
         #link mkt_pin_configure does both.
         
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
      """ )
         
      self.C_Header( """
         unsigned /* "C" */ char mkt_pin_read( int N );
      """ )
      
      self.Documentation( """      
      #article gpio 
         #header MK_GPIO_connect
         #index connect pin, pin connect, function, pin function, GPIO
         
         #interface MK_GPIO_connect
            #parameter N unsigned int 
               number of the IO pin
            #parameter C unsigned int
               connection value for the pin
            
         This function configures (connects) the indicated IO pin as 
         specified by the connection value.
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         
         #index MK_GPIO_is_GPIO
         #anchor MK_GPIO_is_GPIO
         In most ARM chips each pins has 2 bits that
         control the function of that pin. On most ARM chips the value 00
         selects the function GPIO (General Purpose IO) which allows
         the apllication to control the direction of the pin and (when
         the pin is output) its value.
         If you want to configure a pin fort GPIO you can use 
         the pre-defined value MK_GPIO_is_GPIO, but in practice it will be 
         even better to call 
         #link mkt_pin_configure). 
         The effect of the other three configuration values is chip and pin 
         dependent, consult the datasheet for information.
      """ )
                
      self.C_Header( """      
         void /* "C" */ mkt_pin_connect( int N, int C );
      """ )
      
   ##########################################################################
   #
   # LEDs
   #
   ##########################################################################
   
      
   def LEDs( self ):
      
      N  = self.Configuration.Get_Value( Mkt_LEDs_N )             
      HQ = self.Configuration.Get_Value( Mkt_LEDs_595_HQ )
      SQ = self.Configuration.Get_Value( Mkt_LEDs_595_SQ )
      D  = self.Configuration.Get_Value( Mkt_LEDs_595_D )      
      if ( N != None ) | ( HQ != None ) | ( SQ != None ) | ( D != None ):
      
         # if one exists, all must exist
         self.Configuration.Must_Get( Mkt_LEDs_595_HQ )
         self.Configuration.Must_Get( Mkt_LEDs_595_SQ )
         self.Configuration.Must_Get( Mkt_LEDs_595_D )
         
         self.C_Header( """
            void mkt_leds_init( void );
            void mkt_leds_write( unsigned int V );
         """ )         
         
         self.C( """
            //===============================================================
            // The LEDs are connected to a HC595 shift register. which is
            // The HC595 is connected to the GPIO pins as shown below.
            //===============================================================
            
            #define MKT_595_N_LEDS      #N
            #define MKT_595_Hold_Clock  #HQ
            #define MKT_595_Shift_Clock #SQ
            #define MKT_595_Data        #D
            
            unsigned char mkt_leds_must_init = 1;
            
            void mkt_leds_init( void ){
               // the pins we need must be outputs
               mkt_fixed_pin_configure( MKT_595_Hold_Clock,   mkt_output );
               mkt_fixed_pin_configure( MKT_595_Shift_Clock,  mkt_output );
               mkt_fixed_pin_configure( MKT_595_Data,         mkt_output );
               mkt_leds_must_init = 0;
            }         
         
            void mkt_leds_write( unsigned int V ){
               int i;
         
               // for lazy users: always initialise. doesn't do any harm.
               if( mkt_leds_must_init ){ mkt_leds_init(); }
         
               // shift the 8 data bits out
               for( i = 0; i < MKT_595_N_LEDS; i++ ){
                  mkt_fixed_pin_write( MKT_595_Data, ( V & 1 ));
                  mkt_wait_us( 1 );
                  mkt_fixed_pin_clear( MKT_595_Shift_Clock );
                  mkt_wait_us( 1 );
                  mkt_fixed_pin_set( MKT_595_Shift_Clock );
                  mkt_wait_us( 1 );
                  V = V >> 1;
               }
               mkt_fixed_pin_clear( MKT_595_Hold_Clock );
               mkt_wait_us( 1 );
               mkt_fixed_pin_set( MKT_595_Hold_Clock );
               mkt_wait_us( 1 );
            }
         """
            .replace( "#N",  str( N ))
            .replace( "#HQ", str( HQ )) 
            .replace( "#SQ", str( SQ )) 
            .replace( "#D",  str( D )) 
         )
         return
      
      for N in range( 31, 0, -1 ):    
         P = self.Configuration.Get( Mkt_LED_Template % N, None  )
         if P != None:
            Existing = self.Configuration.Get( 
               Mkt_LED_Template % ( N - 1 ), 
               None  )
            if Existing == None:
               self.Configuration.Set_Default( 
                  Mkt_LED_Template % ( N - 1 ), 
                  str( int( P.Value ) - 1 ))
      N = self.Configuration.Get( Mkt_LED_Template % 0, None  )         
      if N != None:
         self.C_Header( """
            void mkt_leds_init( void );
            void mkt_leds_write( unsigned int V );
         """ )         
         
         Text1 = ""
         Text2 = ""
         Prefix = ""
         for N in range( 0, 31 ):
            Pin = self.Configuration.Get_Value( Mkt_LED_Template % N, None  )
            if Pin != None:
               Pin = int( Pin )
               # print( N, Pin )
               Text1 += Prefix + \
                  "mkt_pin_configure( %d, mkt_output );\n" % Pin
               Text2 += Prefix + \
                  "mkt_pin_write( %d, V & ( 1 << %d ));\n" % ( Pin, N )
               Prefix = "               "
         
         self.C( """
            //===============================================================
            // The LEDs are connected  directly to GPIO pins.
            //===============================================================

            void mkt_leds_init( void ){
               // the pins we use must be outputs
               %s
            }         
         
            void mkt_leds_write( unsigned int V ){
               static int must_init = 1;
         
               // for lazy users: always initialise. doesn't do any harm.
               // if( must_init )
               { mkt_leds_init(); }
               must_init = 0;
         
               // set all pins according to V
               %s
            }
         """ % (Text1, Text2 ))            
      
      self.Documentation( """
      #article leds LEDs 
      
         When LEDs are connected to the target chip the 
         function 
         #link mkt_leds_write 
         can be configured to set the value of 
         the (up to 32) LEDs.
         The function 
         #link mkt_leds_init 
         initializes the IO pins for writing
         to the LEDs, but this function is automatically called by 
         mkt_leds_write when that function is first called,
         so it is unlikely that this initialisation function 
         must be called explicitly by the application.
         
         The following example produces a KITT style pattern on 8 LEDs:
         
         #code example kitt.c
            void show( int Pattern ){
               mkt_leds_write( Pattern );
               mkt_wait_us( 200 * 1000 );
            }
            void main( void ){
               while( 1 ){
                  show( 0b00000011 );   
                  show( 0b00000110 );   
                  show( 0b00001100 );   
                  show( 0b00011000 );   
                  show( 0b00110000 );   
                  show( 0b01100000 );   
                  show( 0b11000000 );   
                  show( 0b01100000 );   
                  show( 0b00110000 );   
                  show( 0b00011000 );   
                  show( 0b00001100 );   
                  show( 0b00000110 );   
               }
            }
         #end code
      
      #article leds
         #header mkt_leds_init
      
         #interface mkt_leds_init
            
         The function mkt_leds_init initializes the GPIO pins used for 
         accessing the LEDs, but this function is called automatically by 
         #link mkt_leds_write,
         when it is first called,
         so it is unlikely that you will use this function directly.
            
      #article leds
         #header mkt_leds_write
      
         #interface mkt_leds_write
            #parameter V unsigned int
               values for all LEDs
      
         The function mkt_leds_write first initializes the hardware for
         writing to the LEDs (if not done yet) and then writes the value 
         V to the LEDs.
         Bit 0 of V determines whether LED 0 will be on (a bit value
         of 0 turns the LED off, a 1 turns the LED on), etc.
         The bits at positions higher than the number of LEDs 
         are ignored.
            
      #article leds-x
         #header config-leds Configuring the LED support
         
         For boards supported by MicroKit the support for LEDs is configured
         automatically. The following is relevant only when you must configure
         LEDs for a board that is not supported.
         
         When the LEDs are directly connected to microcontroller pins it 
         is sufficient to
         configure an mkt_leds_pin_... for each LED, with as value the 
         GPIO number of the pin to which the LED is connected. 
         //As an example, the following 
         //configurations are active when a 
         //#link mcb2130 
         //is configured as target board:
         //
         //#code
         //   // configure LEDs for KEIL_MCB2130
         //   #configure mkt_leds_pin_0    48
         //   #configure mkt_leds_pin_1    49
         //   #configure mkt_leds_pin_2    50
         //   #configure mkt_leds_pin_3    51
         //   #configure mkt_leds_pin_4    52
         //   #configure mkt_leds_pin_5    53
         //   #configure mkt_leds_pin_6    54
         //   #configure mkt_leds_pin_7    55
         //#end code
         //
         When LEDs are connected to consequtive pins, it is sufficient to
         configure only the highest numbered LED. Lower numbered LEDs which
         are not configured explicitly are defined implicitly at the pin
         of the higher LED minus one. 
         //Hence the above can be abbreviated to:
         //    
         //#code
         //   #configure mkt_leds_pin_7    55
         //#end code
         
         When LEDs are connected to non-consequtive pins only the highest
         LED of each consequtive range needs to be defined, but for ease
         of reading it might often be better to define all LEDs explicitly.
         
         When LEDs are connected to a chain of one or more HC595-style shift 
         registers
         the pins that connect to the shift register(s) and 
         the number of LEDs must be defined. 
         LED 0 is the first value to be clocked out, in other words:
         It is assumed that LED 0 is the LED most distant from the ARM chip.
         //The following configurations are active when a 
         //#link MK_HU_ARMBOARD_V2 
         //is configured as target board:
         //
         //#code
         //   // configure LEDs for 
         //   mkt_leds_595_hq    16
         //   mkt_leds_595_sq     4 
         //   mkt_leds_595_d      6
         //   mkt_leds_n          8
         //#end code
   """ ) 
   
   ##########################################################################
   #
   # Character LCD (HD44780)
   #
   ##########################################################################
   
   
   def Character_LCD( self ):
   
      self.Configuration.Extrapolate( "clcd_d%d", 7, 4 )  
      CLCD_Type = self.Configuration.Get_Value( mkt_clcd_Type, None )
      
      # print CLCD_Type
      if CLCD_Type != None: self.C( """    
         
         #define mkt_clcd_SLOWDOWN_FACTOR 1
         
         // wait us or ms, use mkt_clcd_SLOWDOWN_FACTOR
         #define mkt_clcd_WAIT_us( x ) \\
            mkt_wait_us( x * mkt_clcd_SLOWDOWN_FACTOR )
         #define mkt_clcd_WAIT_ms( x ) mkt_clcd_WAIT_us( x * 1000 )
                 
         void mkt_clcd_write4( unsigned char n ){
            mkt_clcd_WAIT_us( 1 );
            mkt_pin_write( mkt_clcd_d4, n & 0x01 );
            mkt_pin_write( mkt_clcd_d5, n & 0x02 );
            mkt_pin_write( mkt_clcd_d6, n & 0x04 );
            mkt_pin_write( mkt_clcd_d7, n & 0x08 );
            mkt_clcd_WAIT_us( 10 );
            mkt_pin_write( mkt_clcd_e, 1 );
            mkt_clcd_WAIT_us( 10 );
            mkt_pin_write( mkt_clcd_e, 0 );
            mkt_clcd_WAIT_us( 45 );  // enough for most instructions
         }
         
         unsigned char mkt_clcd_must_init = 1;
         void mkt_clcd_write8( unsigned char isData, unsigned char b ){
            if( mkt_clcd_must_init ){ mkt_clcd_init(); }
            mkt_pin_write( mkt_clcd_rs, isData );
            mkt_clcd_write4( b >> 4 );
            mkt_clcd_write4( b );
         }
   
         void mkt_clcd_init( void ){
         
            // avoid recursive initialisations, so clear the flag now!
            mkt_clcd_must_init = 0;
         
            // the pins we need must be outputs
            mkt_pin_configure( mkt_clcd_d4,  mkt_output );
            mkt_pin_configure( mkt_clcd_d5,  mkt_output );
            mkt_pin_configure( mkt_clcd_d6,  mkt_output );
            mkt_pin_configure( mkt_clcd_d7,  mkt_output );
            mkt_pin_configure( mkt_clcd_e,   mkt_output );
            mkt_pin_configure( mkt_clcd_rs,  mkt_output );
            #ifdef mkt_clcd_PIN_RW
               mkt_pin_configure( mkt_clcd_PIN_RW,  mkt_output );
               mkt_pin_write( mkt_clcd_PIN_RW, 0 );
            #endif
         
            // give LCD time to wake up
            mkt_pin_write( mkt_clcd_e,  0 );
            mkt_clcd_WAIT_ms( 50 ); // was 20
         
            // interface initialisation: make sure the LCD is in 4 bit mode
            // (magical sequence, taken from the HD44780 datasheet)
            mkt_clcd_write4( 0x03 );
            mkt_clcd_WAIT_ms( 5 );
            mkt_clcd_write4( 0x03 );
            mkt_clcd_WAIT_us( 100 );
            mkt_clcd_write4( 0x03 );
            mkt_clcd_write4( 0x02 );     // 4 bit mode
         
            // functional initialisation
            mkt_clcd_command( 0x28 );    // 4 bit mode, 2 lines, 5x8 font
            mkt_clcd_command( 0x0C );    // display on, no cursor, no blink
            mkt_clcd_clear();            // clear display, 'cursor' home
            mkt_clcd_goto_xy( 0, 0 );    // 'cursor' home
         }            
      """ )
        
      self.Documentation( """
         #article char-lcd Character LCD
         #index LCD, HD44780, 44780
         
         The library provides support for a character LCD with an HD44780-type
         controller. The following example alternates between showing
         two texts on such an LCD:
            
         #code hello.c
            void show( const char *s ){
               mkt_clcd_clear();
               while( *s != 0 ){
                  mkt_clcd_char_write( *s++ );
               }
            }
            void main( void ){
               while( 1 ){
                  show( "Hello   " );
                  mkt_wait_us( 200 * 1000 );  
                  show( "   world" );
                  mkt_wait_us( 200 * 1000 );  
               }
            }
         #end code
         
      #article char-lcd-x
         The mkt_clcd_command and mkt_clcd_data are the basic 
         character LCD functions. The effect of these fucntions
         can be found in the HD44780 LCD controller datasheet. 
         Note that some mkt_clcd_command calls will require a delay 
         before the next LCD command, to give the LCD controller
         time to execute the command. 
         
         In most cases these functions will not be called directly,
         use the higher-level functions like
         #link mkt_clcd_clear
         and 
         #link mkt_clcd_char_write
         instead.
      
         #header mkt_clcd_command
         
         #interface mkt_clcd_command
            give direct LCD command
            #parameter cmd unsigned char
               the command
         
         The function mkt_clcd_command sends the command byte cmd
         to the LCD. 
         
         #header mkt_clcd_data
         
         #interface mkt_clcd_data
            send data byte to the LCD 
            #parameter chr unsigned char
               the data byte
         
         The function mkt_clcd_data sends the data byte chr
         to the LCD.
         
      blabla: #section headers
         // I would have prefered this part to be later, after the doucmentation
         // of the configuration, but that does not work, because the headers
         // need the presence of mkt_clcd_TYPE
         
         //#ifndef mkt_clcd_TYPE
         //   #ifdef MK_BOARD_CLCD_TYPE
         //      #define mkt_clcd_TYPE MK_BOARD_CLCD_TYPE
         //   #endif
         //#endif
      """ )
      
      if CLCD_Type != None: self.C_Header( """
         void mkt_clcd_command( unsigned char chr );
         void mkt_clcd_data( unsigned char chr );
      """ )
     
      if CLCD_Type != None: self.C( """              
         // building block for all commands      
         void mkt_clcd_write8( unsigned char isData, unsigned char b );
   
         void mkt_clcd_command( unsigned char cmd ){
            mkt_clcd_write8( 0, cmd );
         }
         
         void mkt_clcd_data( unsigned char chr ){
            mkt_clcd_write8( 1, chr );
         }
      """ )
      
      self.Documentation( """

      #article char-lcd  
         #header mkt_clcd_init
         
         #interface mkt_clcd_init
            initialise the LCD
         
         The function mkt_clcd_init initialises the GPIO pins
         used to access the LCD and initialises the LCD itself.
         
         This function is called automatically on the first
         use of any other character LCD function,
         so it is unlikely that this function needs to be called
         directly form the application.
         
         Calling this function does not clear the display nor
         does it position the write cursor.
         
      """ )
      
      if CLCD_Type != None: self.C_Header( """
         void mkt_clcd_init( void );
      """ )
         
      self.Documentation( """
      #article char-lcd-x  
         #header mkt_clcd_clear
         
         #interface mkt_clcd_clear
            clear and cursor home
         
         The function mkt_clcd_clear clears the LCD and sets 
         the (invisible) write cursor at the top-left position.
         
      """ )
      
      if CLCD_Type != None: self.C_Header( """
            void mkt_clcd_clear( void );  
      """ )
      
      if CLCD_Type != None: self.C( """
         int _mkt_clcd_x, _mkt_clcd_y;
            
         void mkt_clcd_clear( void ){
            mkt_clcd_command( 0x01 );
            mkt_clcd_WAIT_ms( 2 );
            _mkt_clcd_x = _mkt_clcd_y = 0;
         }      
      """ )
      
      self.Documentation( """      
      #article char-lcd  
         #header mkt_clcd_char_write
         
         #interface mkt_clcd_char_write
            print char on LCD
            #parameter c char
               the char
         
         The function mkt_clcd_char_write prints the character c 
         at the current position on the LCD and
         advances the (invisible) write cursor one position to the right.
         Characters that would be written beyond the right boundary
         of the display will be ignored.
         The cursor does not wrap around to a next line.
         When the write cursor is outside the visible part of the LCD
         this function has no effect.
         
         The following characters have a special meaning: 
         
         #list
            '\\n' : puts the write cursor at the start of the next line.
            
            '\\r' : puts the write cursor at the start of the current line.
         
            '\\v' : clears the display and puts the cursor at the 
            top-left position (same effect as calling 
            #link mkt_clcd_clear ()).
            
         #end list
         
         //When the interpretation of these special characters is not
         //desired the function mkt_clcd_char_write_raw can be used instead.
      """ )
      
      if CLCD_Type != None: self.C_Header( """
         void mkt_clcd_char_write( char chr );
      """ )
      
      if CLCD_Type != None: self.C( """         
         void mkt_clcd_char_write( char chr ){
            if( chr == '\\n' ){
               mkt_clcd_goto_xy( 0, _mkt_clcd_x + 1 );
               return;
            }
            if( chr == '\\r' ){
               mkt_clcd_goto_xy( 0, _mkt_clcd_y );
               return;
            }
            if( chr == '\\v' ){
               mkt_clcd_clear();
               return;
            } 
            mkt_clcd_char_write_raw( chr );
         }
      """ )
      
      self.Documentation( """   
      
      #article char-lcd-x
         #header mkt_clcd_char_write_raw
         
         #interface mkt_clcd_char_write_raw
            print char on LCD
            #parameter c char
               the char
         
         The function mkt_clcd_char_write prints the character c and
         advances the (invisible) write cursor one position to the right.
         When the write cursor is outside the visible part of the LCD
         this function has no effect.
         
         In most cases the function mkt_clcd_char_write will be more
         convenient because it handles a few special characters.
         
      """ )
      
      if CLCD_Type != None: self.C_Header( """             
         void mkt_clcd_char_write_raw( char chr );
      """ )
      
      if CLCD_Type != None: self.C( """       
         void mkt_clcd_char_write_raw( char chr ){
            #if mkt_clcd_jump == 1
               if( _mkt_clcd_x == 8 ){
                  mkt_clcd_goto_xy( 8, _mkt_clcd_y );
               }
            #endif
            // don't write outside the boundaries
            if( 
                  ( _mkt_clcd_x < mkt_clcd_columns )
               && ( _mkt_clcd_y < mkt_clcd_lines )
            ){
               mkt_clcd_data( chr );
               _mkt_clcd_x++;
            }
         }      
      """ )
      
      self.Documentation( """ 
            
      #article char-lcd-x  
         #header mkt_clcd_goto_xy
         
         #interface mkt_clcd_goto_xy
            put cursor at location x, y
            #parameter x unsigned int
               x location
            #parameter y unsigned int
               y location
         
         The function mkt_clcd_goto_xy places the invisible write
         cursor at location (x,y). The top-left position is (0,0).
         
      """ )
      
      if CLCD_Type != None: self.C_Header( """             
         void mkt_clcd_goto_xy( unsigned char x, unsigned char y );
      """ )
      
      if CLCD_Type != None: self.C( """       
         void mkt_clcd_goto_xy( unsigned char x, unsigned char y ){
            _mkt_clcd_x = x;
            _mkt_clcd_y = y;
            #if mkt_clcd_jump == 1
               if( x < 8 ){
                  mkt_clcd_command( 0x80 + x );
               } else {
                  mkt_clcd_command( 0x80 + 0x40 + ( x - 8 ));
               }
            #else
               mkt_clcd_command( 0x80 + 
                  (( y > 0 ) ? 0x40 : 0x00 ) 
                  + ( x ));
            #endif
         }      
      """ )
      
      self.Documentation( """       
      #article char-lcd-x  
         #header mkt_clcd_goto_x
         
         #interface mkt_clcd_goto_x
            put cursor at location x
            #parameter x unsigned int
               x location
         
         The function mkt_clcd_goto_x places the invisible write
         cursor at location x on the current line. 
         The top-left position is (0,0).
         
      """ )
      
      if CLCD_Type != None: self.C_Header( """             
         void mkt_clcd_goto_x( unsigned char x );
      """ )
      
      if CLCD_Type != None: self.C( """       
         void mkt_clcd_goto_x( unsigned char x ){
            mkt_clcd_goto_xy( x, _mkt_clcd_y );
         }
      """ )
      
      self.Documentation( """       
      #article char-lcd-x  
         #header mkt_clcd_define_one
         
         #interface mkt_clcd_define_one
            define one user-defined character
            #parameter x unsigned char
               the char
            #parameter p unsigned char [8]
               8 bytes defining the char
         
         The function mkt_clcd_define_one defines the user-defined
         character x (must be 0..7) according to the 8-byte pattern 
         pointed to by p.
      
      """ )
      
      if CLCD_Type != None: self.C_Header( """             
            void mkt_clcd_user_define_one( 
               char chr, unsigned char pattern[8] );   
      """ )
      
      if CLCD_Type != None: self.C( """       
         void mkt_clcd_user_define_one( 
            char chr, 
            unsigned char pattern[8] 
         ){
         }
      """ )
      
      self.Documentation( """       
      #article char-lcd-x  
         #header mkt_clcd_define_all
         
         #interface mkt_clcd_define_all
            defines the 8 user-defined characters
            #parameter p unsigned char [8][8]
               8 blocks of 8 bytes defining the 8 chars
         
         The function mkt_clcd_define_all defines the 8 user-defined
         characters according to the 8 * 8 bytes pointed to by p.
         
      """ )
      
      if CLCD_Type != None: self.C_Header( """             
         void mkt_clcd_user_define_all( 
            unsigned char pattern[8][8] );           
      """ )
      
      if CLCD_Type != None: self.C( """             
         void mkt_clcd_user_define_all( 
            unsigned char pattern[8][8] 
         ){
         }
      """ )
      
      self.Documentation( """                            
      #article char-lcd-x
         #header Configuring a character LCD
         #index mkt_clcd_TYPE
         
         For boards supported by the library the support for a character LCD 
         is configured automatically. 
         The following is relevant only when you must configure
         a character LCD for a board that is not supported by the library.
      
         #anchor mkt_clcd_TYPE
         If mkt_clcd_TYPE is defined it specifies the size
         (lines and columns) of the HD44780-compatible character LCD that is 
         connected to the ARM chip. 
         It can be configured as one of the values 
         MK_CHAR_LCD_1x8,
         MK_CHAR_LCD_1x16,
         MK_CHAR_LCD_1x16L,
         MK_CHAR_LCD_2x16,
         MK_CHAR_LCD_4x20.
         
         The value MK_CHAR_LCD_1x16 is for the common 16x1 type that has an 
         address jump between columns 8 and 9, 
         MK_CHAR_LCD_1x16L is for the more rare type that does not have this 
         discontinuity. 
         
         When MK_BOARD is specified and the board has an LCD you can omit 
         mkt_clcd_TYPE, it will default to the LCD on that board. 
         But you can still define a different mkt_clcd_TYPE if you want to.
         
         #anchor mkt_clcd_LINES, mkt_clcd_COLUMNS, mkt_clcd_jump
         If your HD44780-compatible LCD does not match one of the predefined types 
         for mkt_clcd_TYPE you can define your own by defining 
         mkt_clcd_LINES and mkt_clcd_COLUMNS. 
         Define mkt_clcd_jump as 1 if your LCD has the address jump between 
         columns 8 and 9 of line 1.
         The configuration below would be for a 1x20 LCD with an address jump at 8:
         
         #literal
            #configure mkt_clcd_LINES        1
            #configure mkt_clcd_COLUMNS     20
            #configure mkt_clcd_jump   1   
         #end literal
         
         The configuration items mkt_clcd_PIN_D4 .. mkt_clcd_PIN_D7 
         define the chip pins that are 
         connected to the corresponding LCD data lines. 
         Except for mkt_clcd_PIN_D7 these definitions can be omitted. 
         Omitted pins default to the next higher pin minus one. 
         mkt_clcd_e and mkt_clcd_rs define the chip pins that 
         connect to the corresponding LCD control lines. 
         These definitions can not be omitted.
            
         When mkt_clcd_SLOWDOWN_FACTOR is defined all delays in the interfacing 
         to the LCD are multiplied by this factor. 
         Some LCDs require more delay between various operations than 
         the standard LCD. An extreme slowdown factor (for instance 10) 
         can be used to quickly identify this type of problem.
            
         For a very slow LCD 2x20 character LCD, 
         connected to the GPIO pins 0..3,
         control lines on pins 4 and 5, the
         following configuration would be appropriate (but the lines
         for mkt_clcd_PIN_D4 .. mkt_clcd_PIN_D6 could be omitted):
         
         #literal
            #configure mkt_clcd_LINES            20
            #configure mkt_clcd_COLUMNS           2
            #configure mkt_clcd_PIN_D4            0
            #configure mkt_clcd_PIN_D5            1
            #configure mkt_clcd_PIN_D6            2
            #configure mkt_clcd_PIN_D7            3
            #configure mkt_clcd_e             4
            #configure mkt_clcd_rs            5
            #configure mkt_clcd_SLOWDOWN_FACTOR   1
         #end literal
      
      """ )
      
   ##########################################################################
   #
   # Keypad 
   #
   ##########################################################################
      
   def Keypad( self ):
   
      Keypad_Type = self.Configuration.Get_Value( "keypad_type", None )
      if Keypad_Type == None:      
         return
      
      if Keypad_Type == Mkt_Keypad_HUV4:
         self.C_Header( """                
            enum mkt_key_enum {
               mkt_key_0 = 5,     mkt_key_1 = 11,    mkt_key_2 = 10, 
               mkt_key_3 = 9,     mkt_key_4 = 8,     mkt_key_5 = 15, 
               mkt_key_6 = 14,    mkt_key_7 = 13,    mkt_key_8 = 12, 
               mkt_key_9 = 7,     mkt_key_a = 3,     mkt_key_b = 2,  
               mkt_key_c = 1,     mkt_key_d = 0,     mkt_key_star = 6,  
               mkt_key_sharp = 4, mkt_key_none = 0xFF
            };
            #ifdef __cplusplus
               #define mkt_key mkt_key_enum
            #else
               #define mkt_key enum mkt_key_enum
            #endif 
            void mkt_kbd_init( void );
            int mkt_kbd_read_all( void );
            unsigned char mkt_kbd_is_pressed( mkt_key key );
         """ )

         self.C( """                
            #define pin_dat 21
            #define pin_clk 22
            #define pin_req ( 25 + 32 )


            void mkt_kbd_init( void ){

               mkt_pin_configure( pin_clk, mkt_output );
               mkt_pin_configure( pin_dat, mkt_input );
               mkt_pin_configure( pin_req, mkt_input );

               // start with clock low
               mkt_pin_clear( pin_clk );
            }

            unsigned char mkt_kbd_init_done = 0;

            int mkt_kbd_read_all( void ){
							int data = 0;
							int i;

              if( ! mkt_kbd_init_done ){
                  mkt_kbd_init_done = 1;
                  mkt_kbd_init();
              }

							// start a conversion
							mkt_pin_set( pin_clk );

							// the documentation says 30
							// add some margin
							mkt_busy_wait_us( 50 );

							// Read data
							for( i = 0; i < 16; i++ ){
            
								// Generate a falling edge
								mkt_pin_clear( pin_clk );

								// Shift bit
								data = data << 1;   

								// Data's clocked out on rising edge
								// so read in after the falling edge
								data |= mkt_pin_read( pin_dat );

								// Data is clocked out on the rising edge
								mkt_pin_set( pin_clk );

								// 25 seems to be enough.
								// add some margin
								mkt_busy_wait_us( 35 );
							}
							return  data;
            }
                        
            unsigned char mkt_kbd_is_pressed( mkt_key key ){
                int data = mkt_kbd_read_all();                
                
               // print( "\\n" );
               // iprint( "d", data );
               // iprint( "k", key );
               // iprint( "m", ( 1 << (int) key ) );
               
               if( key == mkt_key_none ){ 
                  return ( data == 0 );
               } else {
                  return ( data & ( 1 << (int) key )) != 0;
               }
            }
           
         """ )                  
       
   ##########################################################################
   #
   # print (character output)
   #
   ##########################################################################
      
   def Print( self ):
   
      self.C_Header( """                
         extern void (*mkt_print_vector)( char c );
         void mkt_char_print( char c );
         void mkt_string_print( const char *s );
         void mkt_decimal_print( int n );
         void mkt_hexadecimal_print( int n );
      """ )
         
      self.C( """                
         void mkt_dummy_print( char c ){}
         
         void (*mkt_print_vector)( char c ) = mkt_dummy_print;
         void mkt_char_print( char c ){
            (*mkt_print_vector)( c );
         }
         void mkt_string_print( const char *s ){
            while( *s != '\\0' ){
               mkt_char_print( *s++ );
            }
         }
         void mkt_decimal_pos_write( int x, int n ){
            int p;
            if( n > 0 ){
               p = x % 10;
               mkt_decimal_pos_write( x / 10, n - 1 );
               mkt_char_print( '0' + p );
            }
         }
         void mkt_decimal_print( int n ){
            mkt_decimal_pos_write( n, 8 );
         }
         void mkt_hexadecimal_1_print( int n ){
            n &= 0x0F;
            if( n < 10 ){
               mkt_char_print( '0' + n );
            } else {
               mkt_char_print( 'A' + ( n - 10 ));
            }
         }
         void mkt_hexadecimal_print( int n ){
            int i;
            for( i = 28; i >= 0; i-= 4 ){
               mkt_hexadecimal_1_print( n >> i );
            }
         }
      """ )                  
             
   ##########################################################################
   #
   # Graphic LCD - common
   #
   ##########################################################################
      
   def Graphic_LCD_Common( self ):
   
      GLCD_Type = self.Configuration.Get_Value( "glcd_type", None )
      if GLCD_Type == None:
         return
      
      self.Documentation( """
         #article graphic-lcd  
         #header interface
         
         The library provides a basic interface to graphic LCDs. 
         The interface functions are:
         #list
            #link mkt_glcd_init  : initialize the LCD interface
            #link mkt_glcd_clear : clear the CLD
            #link mkt_glcd_pixel_write : write a single pixel
            #link mkt_glcd_block_write : write a rectangular block of pixels
         #end list
                  
         To the graphic LCD interface you must specify the type of
         graphic LCD uses, the size of the LCD, and the microcontroller
         pins thar connect to the LCD. The details are different for
         each type of LCD. The supported types are:
         #list
            #paragraph ks0108
            #paragraph t6369
         #end list             
      """ )
      
      self.C( """                
         // wait macro's for glcd
         #define mkt_glcd_SLOWDOWN_FACTOR 1         
         #define mkt_glcd_wait_us( x ) \\
            mkt_wait_us( x * mkt_clcd_SLOWDOWN_FACTOR )
         #define mkt_glcd_wait_ms( x ) mkt_clcd_WAIT_us( x * 1000 )
      """ )         

      self.Documentation( """
        #article graphic-lcd
         #header mkt_glcd_init
         
         #interface mkt_clcd_init
            initializes the graphic LCD interface
         
         This function initializes the graphic LCD interface.
         It is called automatically when any other graphic interface function
         is called, so in normal use mkt_clcd_init need not be called
         explicitly.
      """ )

      self.C_Header( """                
         void mkt_glcd_init( void );
      """ )
      
      self.Documentation( """
        #article graphic-lcd
         #header mkt_glcd_clear
         
         #interface mkt_glcd_clear
            clears the graphic LCD
         
         This function clear the graphic LCD.
      """ )

      self.C_Header( """                
         void mkt_glcd_clear( void );
      """ )
      
      self.Documentation( """
         #article graphic-lcd
         #header mkt_glcd_pixel_write
         
         #interface mkt_glcd_pixel_write
            writes a single pixel
            #parameter x int
               x location of the pixel
            #parameter y int
               y location of the pixel
            #parameter mode int
               the write mode, see description
         
         The function mkt_glcd_pixel_write writes a single pixel on the display.
         
         Then mode parameter determines what happens to the bit:
         #list
            #paragraph mkt_set : the pixel is set
            #paragraph mkt_clear : the pixel is cleared
            #paragraph mkt_flip : the pixel is inverted            
         #end list 
      """ )
      
      self.C_Header( """                
         #define mkt_set    #UNIQUE
         #define mkt_clear  #UNIQUE
         #define mkt_flip   #UNIQUE
         #define mkt_write  #UNIQUE
         void mkt_glcd_pixel_write( int x, int y, int mode );
      """ )
      
      self.Documentation( """
         #article graphic-lcd
         #header mkt_glcd_block_write
         
         #interface mkt_glcd_block_write
            writes a rectangular block of pixels on the LCD
            #parameter gx int
               top-left x coordinate on the LCD
            #parameter gy int
               top-left y coordinate on the LCD
            #parameter xbits int
               x size of write area on the LCD
            #parameter ybits int
               y size of write area on the LCD
            #parameter data const unsigned char *
               pointer to the source data
            #parameter xstart int
               top-left x offset in the source data
            #parameter ystart int
               top-left y-offset in the source data
            #parameter stride int
               length of one line of source data, in bytes
            #parameter mode int
               the write mode, see description
         
         The function mkt_glcd_block_write writes a rectangular block
         of pixels from memory to the LCD. The first four parameters
         (gx, gy, xbits, ybits) specify the area on the LCD. 
         
         The data parameter must point to a memory area that contains the
         bits that are to be written. The bits must be stored 8-pixels
         per byte, x-first. The xstart and ystart specify an offset
         within the data area. The stride specifies the length of one 
         line (x-direction) in the aea, in bytes.
                  
         Then mode parameter determines how each bit is written:
         #list
            #paragraph mkt_set : the bit is set according to the source data
            #paragraph mkt_clear : the bit is cleared
            #paragraph mkt_flip : the bit is inverted 
            #paragraph mkt_write : the bit is inverted            
         #end list          
      """ )
      
      self.C_Header( """                
         void mkt_glcd_block_write( 
            int gx, int gy,            
            int xbits, int ybits, 
            const unsigned char *data, 
            int xstart, int ystart, 
            int stride,
            int mode );
      """ )
      
      self.Documentation( """
         #article graphic-lcd
         #header mkt_glcd_line
         
         #interface mkt_glcd_line
            writes a line
            #parameter x0 int
               x location of the start
            #parameter y0 int
               y location of the start
            #parameter x1 int
               x location of the end
            #parameter y1 int
               y location of the end
            #parameter mode int
               the pixel write mode, see description 
               #link mkt_glcd_pixel_write
         
         The function mkt_glcd_bit_line writes a line on the display.
         
         The following program writes a nice set of patterns to a display.
         It does so by writing lines from a point on one edge to a point 
         on the opposite edge, and steppen these points along the edges.
         Each line is written using the mkt_flip mode, which cause each
         pixel that is written to be inverted. After a pause the sequence
         is repeated, but the step size (along the edges) is doubled.
         
         #code
            // add #configure lines here
         
            void mkt_glcd_pattern( int n, int m ){
               int x,y,z;
               mkt_glcd_clear();
               for( z = 1; z < 17; z = 2 * z ){
                  for( x = 0; x < 128; x = x + z ){
                    mkt_glcd_line( x ,0 ,128-x,63, mkt_flip);
                  }        
                  for( y = 0; y < 63; y = y + z ){
                     mkt_glcd_line( 127 ,y ,0 ,64-y, mkt_flip);
                  }       
                  mkt_wait_us( m );
               }
            }
            
            int main( void ){
               int dummy = 0;
               while(1){
                  mkt_glcd_pattern( 0, 3 * 1000 * 1000 );
               }  
               return dummy;
            }
         #end code
      """ )
        
      self.C_Header( """
         void mkt_glcd_line( int x0, int y0, int x1, int y1, int mode );
      """ )
      
      self.C( """
         #define abs( x ) ((x>0)?(x):(-x))
         #define SWAP( x, y ){ int z; z = y; y = x; x = z; }
         // was: (x ^= (y ^= (x ^= y)))
         
         void mkt_glcd_line( int x0, int y0, int x1, int y1, int mode ){
            // http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
            int x;
            int Dx = x1 - x0; 
            int Dy = y1 - y0;
            int steep = (abs(Dy) >= abs(Dx));
            if( steep ){
               SWAP(x0, y0);
               SWAP(x1, y1);
               // recompute Dx, Dy after swap
               Dx = x1 - x0;
               Dy = y1 - y0;
            }
            int xstep = 1;
            if( Dx < 0 ){
               xstep = -1;
               Dx = -Dx;
            }
            int ystep = 1;
            if( Dy < 0 ){
               ystep = -1;    
               Dy = -Dy; 
            }
            int TwoDy = 2*Dy; 
            int TwoDyTwoDx = TwoDy - 2*Dx; // 2*Dy - 2*Dx
            int E = TwoDy - Dx; //2*Dy - Dx
            int y = y0;
            int xDraw, yDraw;  
            for( x = x0; x != x1; x += xstep ){    
               if (steep) {     
                  xDraw = y;
                  yDraw = x;
               } else {     
                  xDraw = x;
                  yDraw = y;
               }
               // plot
               mkt_glcd_pixel_write( xDraw, yDraw, mode);
               // mkt_wait_us( 1000 * 1000 );
               // next
               if( E > 0 ){
                  E += TwoDyTwoDx; //E += 2*Dy - 2*Dx;
                  y = y + ystep;
               } else {
                  E += TwoDy; //E += 2*Dy;
               }
            }
         }
      """ )
         
      self.Documentation( """
         #article graphic-lcd
         #header mkt_glcd_circle
         
         #interface mkt_glcd_circle
            writes a line
            #parameter x0 int
               x location of the centre 
            #parameter y0 int
               y location of the centre
            #parameter radius int
               radiusof the circle
            #parameter mode int
               the pixel write mode, see description 
               #link mkt_glcd_pixel_write
         
         The function mkt_glcd_bit_line writes a circle on the display.
      """ )
        
      self.C_Header( """
         void mkt_glcd_circle(int x0, int y0, int radius, int mode);
      """ )
      
      self.C( """
         void mkt_glcd_circle(int x0, int y0, int radius, int mode){
            // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
            int f = 1 - radius;
            int ddF_x = 1;
            int ddF_y = -2 * radius;
            int x = 0;
            int y = radius;
          
            mkt_glcd_pixel_write(x0, y0 + radius, mode);
            mkt_glcd_pixel_write(x0, y0 - radius, mode);
            mkt_glcd_pixel_write(x0 + radius, y0, mode);
            mkt_glcd_pixel_write(x0 - radius, y0, mode);
          
            while(x < y){
               //assert(ddF_x == 2 * x + 1);
               //assert(ddF_y == -2 * y);
               //assert(f == x*x + y*y - radius*radius + 2*x - y + 1);
               if( f >= 0 ){
                 y--;
                 ddF_y += 2;
                 f += ddF_y;
               }
               x++;
               ddF_x += 2;
               f += ddF_x;    
               mkt_glcd_pixel_write(x0 + x, y0 + y, mode);
               mkt_glcd_pixel_write(x0 - x, y0 + y, mode);
               mkt_glcd_pixel_write(x0 + x, y0 - y, mode);
               mkt_glcd_pixel_write(x0 - x, y0 - y, mode);
               mkt_glcd_pixel_write(x0 + y, y0 + x, mode);
               mkt_glcd_pixel_write(x0 - y, y0 + x, mode);
               mkt_glcd_pixel_write(x0 + y, y0 - x, mode);
               mkt_glcd_pixel_write(x0 - y, y0 - x, mode);
            }
         }
      """ )
      
      Picture = """
         // picture type
         // stride is the number of bytes in a horizontal line
         // x_size and y_size are in bits
         // format is 0 for black-and-white (1 bit per pixel)
         // pixel data is stored x-first
         typedef struct { 
            short int x_size; 
            short int y_size; 
            short int stride; 
            short int format;
            const unsigned char *pixels;
         } mkt_picture;
      """

      self.Documentation( """
         #article graphic-lcd
         #header mkt_picture
         
         #interface mkt_picture
            includes picture data into the application
            #parameter name string
               name of the picture structure
            #parameter file string
               file name of the picture 

         The pseudo-function mkt_picture causes the indicated file name
         to be read and translated to picture data. 
         This picture data is included in the application and can be used 
         for instance to display the picture on a graphic LCD screen. 
         The type of picture data is a structure:
         
         #code %s         
         #end code
         
         This pseudo-function is handled by the MicroKit tool.
         It must be alone on a line, and occupy a single line.
         It is replaced by its expansion before the file is processed 
         by the C compiler, so no C preprocessing is done on the line.
      """ % Picture )
        
      self.C_Header( Picture )
      
      Show = """
         void mkt_glcd_picture( 
            int x, 
            int y, 
            const mkt_picture * picture
         ){
            mkt_glcd_block_write( 
               x, y, 
               picture->x_size, picture->y_size, 
               picture->pixels, 
               0, 0, 
               picture->stride,
               mkt_write 
            );       
         }
      """
      
      self.Documentation( """
         #article graphic-lcd
         #header mkt_picture
         
         #interface mkt_picture
            shows a picture on the graphics LCD
            #parameter x int
               top-left corner on the LCD
            #parameter y int
               top-left corner on the LCD
            #parameter image const mkt_picture *
               image 

         The function mkt_picture shows the picture on a graphic LCD.
         This function is a simple wrapper for mkt_glcd_block_write:
                  
         #code %s         
         #end code
      """ % Show )
        
      self.C_Header( """
         void mkt_glcd_picture( int x, int y, const mkt_picture * picture );
      """ )
      
      self.C( Show )
            
      Font = """
         // font type
         // picture is a picture of the characters in the font, 
         //    stored as one long line
         // when list is NULL the characters 0x20 .. 0x7F are supported,
         //    otherwise it is a (0-terminated) list of characters
         // for a fixed-width font x_size is the width of a char,
         //    and start is NULL
         // for a proportional font x_size is 0, and
         //    start points to an array with the x-offsets of each
         //    character. The first offset is of course 0, but
         //    still stored, and there are 0x61 offsets (not 0x60!)
         typedef struct { 
            short int x_size; 
            short int y_size; 
            const char *list;
            const short int *start; 
            const mkt_picture *picture;
         } mkt_font;         
      """
      
      self.Documentation( """
         #article graphic-lcd
         #header mkt_font
         
         #interface mkt_font
            includes picture data into the application
            #parameter name string
               name of the font structure
            #parameter file string
               file name of the font
            #parameter size int
               size of the included font

         The pseudo-function mkt_font causes the indicated font file name
         to be read, translated to a bitmapped font of the indicated size,
         and be included in the application as a font structure:
         
         #code %s         
         #end code
         
         This pseudo-function is handled by the MicroKit tool.
         It must be alone on a line, and occupy a single line.
         It is replaced by its expansion before the file is processed 
         by the C compiler, so no C preprocessing is done on the line.
      """ % Font )
      
      self.C_Header( Font );
      
      self.Documentation( """
         #article graphic-lcd
         #header mkt_font
         
         #interface mkt_font
            includes picture data into the application
            #parameter c char
               the character to write
            #parameter font * mkt_font
               pointer to the font to be used
            #parameter mode int
               the mode to be used in writing

         This function writes the char c to the graphic lcd,
         using the indicated font and mode.
         It maintains a current location (invisible cursor) that
         is updated appropriately.
         
         The following characters have a special meaning: 
         
         #list
            '\\n' : puts the write cursor at the start of the next line.
            
            '\\r' : puts the write cursor at the start of the current line.
         
            '\\v' : clears the display and puts the cursor at the 
            top-left position             
         #end list         
      """ )
      
      self.C_Header( """
         extern int mkt_glcd_char_x;
         extern int mkt_glcd_char_y;   
         extern short int mkt_glcd_default_mode;   
         extern const mkt_font *mkt_glcd_default_font;
         
         int mkt_font_y_size( const mkt_font *font, char c );
            
         int mkt_font_x_size( const mkt_font *font, char c );
            
         int mkt_font_offset( const mkt_font *font, char c );
      """ )

      self.C( """
         int mkt_glcd_char_x       = 0;
         int mkt_glcd_char_y       = 0;   
         short int mkt_glcd_default_mode = mkt_write;   
         const mkt_font *mkt_glcd_default_font = 0;

         #define mkt_glcd_char_0 ' '
         
         int mkt_font_y_size( const mkt_font *font, char c ){
            return font->y_size;   
         }   
            
         int mkt_font_x_size( const mkt_font *font, char c ){
            if( font->x_size != 0 ){
               return font->x_size;   
            } else {
               return 
                  font->start[ ( c + 1 ) - mkt_glcd_char_0 ] 
                  - font->start[ c - mkt_glcd_char_0 ];
            }   
         }   
            
         int mkt_font_offset( const mkt_font *font, char c ){
            if( font->x_size != 0 ){
               return font->x_size * (c - mkt_glcd_char_0) ;
            } else {
               return font->start[ c - mkt_glcd_char_0 ];
            }
         }      
      """ )

      self.Documentation( """
         #article graphic-lcd
         #header mkt_glcd_detailed_char_write
         
         #interface mkt_glcd_detailed_char_write
            writes a single character to a graphic LCD
            #parameter c char
               the character to write
            #parameter font * mkt_font
               pointer to the font to be used
            #parameter mode int
               the mode to be used in writing

         This function writes the char c to the graphic lcd,
         using the indicated font and mode.
         It maintains a current location (invisible cursor) that
         is updated appropriately.
         
         The following characters have a special meaning: 
         
         #list
            '\\n' : puts the write cursor at the start of the next line.
            
            '\\r' : puts the write cursor at the start of the current line.
         
            '\\v' : clears the display and puts the cursor at the 
            top-left position             
         #end list         
      """ )
      
      self.C_Header( """
         void mkt_glcd_detailed_char_write( 
            char c, 
            const mkt_font *font, 
            int mode 
         );
      """ )

      self.C( """               
         void mkt_glcd_detailed_char_write( 
            char c, 
            const mkt_font *font, 
            int mode 
         ){
              int xs, ys, offset;
            if( font == 0 ) return;
              if( c == '\\n' ){
                 mkt_glcd_char_x = 0;      
                 mkt_glcd_char_y += mkt_font_y_size( font, ' ' );
                 return;
              }
              if( c == '\\r' ){
                 mkt_glcd_char_x = 0;      
                 return;
             }
             if( c == '\\v' ){
                 mkt_glcd_char_x = 0;      
                 mkt_glcd_char_y = 0;      
                 mkt_glcd_clear();
                 return;          
             }
           if(( c < ' ' ) | ( c > '~' )) return;
           xs = mkt_font_x_size( font, c );   
           ys = mkt_font_y_size( font, c );   
           offset = mkt_font_offset( font, c );   
           mkt_glcd_block_write( 
              mkt_glcd_char_x, mkt_glcd_char_y, 
              xs, ys, 
              font->picture->pixels,
              offset, 0, 
              font->picture->stride,
              mode
           );
           mkt_glcd_char_x += xs;
        }         
      """ )
      
      self.Documentation( """
         #article graphic-lcd
         #header mkt_glcd_char_write
         
         #interface mkt_char_write
            includes picture data into the application
            #parameter c char
               the character to write
            #parameter font * mkt_font
               pointer to the font to be used
            #parameter mode int
               the mode to be used in writing

         This function writes the char c to the graphic lcd,
         using the indicated font and mode.
         It maintains a current location (invisible cursor) that
         is updated appropriately.
         
         The following characters have a special meaning: 
         
         #list
            '\\n' : puts the write cursor at the start of the next line.
            
            '\\r' : puts the write cursor at the start of the current line.
         
            '\\v' : clears the display and puts the cursor at the 
            top-left position             
         #end list         
      """ )
      
      self.C_Header( """
         void mkt_glcd_char_write( char c );
      """ )

      self.C( """               
         void mkt_glcd_char_write( char c ){
            mkt_glcd_detailed_char_write( 
               c, 
               mkt_glcd_default_font, 
               mkt_glcd_default_mode
            );   
         }
      """ )               
      
      if 0 : self.C( """
         void mkt_glcd_image_scroll_one( const mkt_picture * image ){
              int offset;
            mkt_glcd_clear();
            for( offset = 0; offset + mkt_glcd_v < image->y_size; offset++ ){
               mkt_glcd_block_write( 
                  0, 0,
                  image->x_size, image->y_size, image->pixels, 
                  0, offset, 
                  image->stride,
                  mkt_write );   
               mkt_wait_us( 100 * 1000 );
            }   
            mkt_wait_us( 1000 * 1000 );
         }   
      """ )      
      

   ##########################################################################
   #
   # Graphic LCD - KS0108
   #
   ##########################################################################
      
   def Graphic_LCD_KS0108( self ):
   
      GLCD_Type = self.Configuration.Get_Value( mkt_glcd_type, None )
      if 0: print( ">>>", GLCD_Type, mkt_glcd_type, mkt_ks0108 )
      if mkt_glcd_type != mkt_ks0108:
         return
        
      self.Configuration.Extrapolate( "glcd_d%d", 7 )  
      
      In_RAM = ""
      Always_Inline = ""
      if 0:
         In_RAM = '__attribute__(( long_call, section( ".data" )))'      
         Always_Inline = "inline __attribute__(( always_inline ))"
      
      self.C( """             
         #define MKT_KS0108_OFF         0x3E
         #define MKT_KS0108_ON          0x3F
         #define MKT_KS0108_FIRST_LINE  0xC0
         #define MKT_KS0108_PAGE        0xB8
         #define MKT_KS0108_ADDRESS     0x40
         
         #define mkt_glcd_use_buffer       1
         #define mkt_glcd_remember_address 1
         
         #define mkt_glcd_c_h              2
         #define mkt_glcd_c_v              1
         #define mkt_glcd_n_controllers (mkt_glcd_c_h * mkt_glcd_c_v)
         
         #if mkt_glcd_use_buffer == 1
            unsigned char mkt_glcd_buffer[ mkt_glcd_h * mkt_glcd_v / 8 ];
         #endif
         
         void mkt_glcd_chip( int chip ){
            // cs pins are active low
            mkt_fixed_pin_write( mkt_glcd_cs1, ! ( chip == 0 ));
            mkt_fixed_pin_write( mkt_glcd_cs2, ! ( chip == 1 ));
         }
         
         void mkt_glcd_direction( int direction ){
            mkt_fixed_pin_direction( mkt_glcd_d0, direction );
            mkt_fixed_pin_direction( mkt_glcd_d1, direction );
            mkt_fixed_pin_direction( mkt_glcd_d2, direction );
            mkt_fixed_pin_direction( mkt_glcd_d3, direction );
            mkt_fixed_pin_direction( mkt_glcd_d4, direction );
            mkt_fixed_pin_direction( mkt_glcd_d5, direction );
            mkt_fixed_pin_direction( mkt_glcd_d6, direction );
            mkt_fixed_pin_direction( mkt_glcd_d7, direction );
         }
         
         IN_RAM void mkt_glcd_write( int x ){
         
            #ifdef mkt_glcd_rw 
               #if mkt_glcd_use_buffer == 0
               
                  // select write
                  mkt_fixed_pin_write( mkt_glcd_rw, 0 );
               
                  // make the data pins outputs
                  mkt_glcd_direction( mkt_output );
                  
               #endif
            #endif
         
            // put the data byte on the data out pins
            mkt_fixed_pin_write( mkt_glcd_d0, x & ( 1 << 0 ));
            mkt_fixed_pin_write( mkt_glcd_d1, x & ( 1 << 1 ));
            mkt_fixed_pin_write( mkt_glcd_d2, x & ( 1 << 2 ));
            mkt_fixed_pin_write( mkt_glcd_d3, x & ( 1 << 3 ));
            mkt_fixed_pin_write( mkt_glcd_d4, x & ( 1 << 4 ));
            mkt_fixed_pin_write( mkt_glcd_d5, x & ( 1 << 5 ));
            mkt_fixed_pin_write( mkt_glcd_d6, x & ( 1 << 6 ));
            mkt_fixed_pin_write( mkt_glcd_d7, x & ( 1 << 7 ));
         
            // toggle the E pin
            mkt_fixed_pin_write( mkt_glcd_e, 1 );
            mkt_wait_us( 1 );
            mkt_fixed_pin_write( mkt_glcd_e, 0 );
            mkt_wait_us( 1 );   
         }
         
         void mkt_glcd_command_write( int command ){
         
            // select command
            mkt_fixed_pin_write( mkt_glcd_di, 0 );
         
            // do the write
            mkt_glcd_write( command );
         }
         
         #if mkt_glcd_remember_address != 0
            int mkt_glcd_current_chip = -1;
            int mkt_glcd_current_page, mkt_glcd_current_address;
         #endif
         
         #if mkt_glcd_use_buffer == 1
            int mkt_glcd_save_index;
         #endif   
         
         // for a two-chip dipslay:
         //    x input bits:   6    5   4   3   2   1   0
                  //          chip  ======== x ==========
         //    y input bits:   5   4    3   2   1   0 
                  //           = y byte =   = y bit =
         void mkt_glcd_address( int x, int y ){
              int new_chip, new_page, new_address;
             
              // don't try to access beyond the boundaries 
            x = x & 0x7F;
            y = y & 0x3F;
         
            // if needed: remember the current buffer index
            #if mkt_glcd_use_buffer == 1   
               mkt_glcd_save_index = x + (( y / 8 ) * 128 );
            #endif
            
            // determine the chip, page and address components
            new_chip = ( x >> 6 ) & 0x01;
            new_page = ( y >> 3 ) & 0x07;
            new_address = x & 0x3F;
            
            #if 0
               print( "\\n===" );
               print( " x=" );phex( x );
               print( " y=" );phex( y );
               print( " : " );phex( new_chip );
               print( " " );phex( new_page );
               print( " " );phex( new_address );
               print( " : " );phex( mkt_glcd_current_chip );
               print( " " );phex( mkt_glcd_current_page );
               print( " " );phex( mkt_glcd_current_address );
            #endif
            
            #if mkt_glcd_remember_address != 0
            
               // if the new address is the same as the old one
               // (possibly updated by auto-increment) setting
               // the new address can be avoided
               if( 
                    ( new_chip     != mkt_glcd_current_chip )
                  | ( new_page     != mkt_glcd_current_page )
                  | ( new_address  != mkt_glcd_current_address )
               ){
                  
                    // set the enw address
                  mkt_glcd_chip( new_chip );
                  mkt_glcd_command_write( MKT_KS0108_PAGE + new_page );
                  mkt_glcd_command_write( MKT_KS0108_ADDRESS + new_address );
                  
                  // remember the new address
                  mkt_glcd_current_chip     = new_chip;
                  mkt_glcd_current_page     = new_page;
                  mkt_glcd_current_address  = new_address;            
               }
            #else
            
               // set the new address
               mkt_glcd_chip( new_chip );
               mkt_glcd_command_write( MKT_KS0108_PAGE + new_page );
               mkt_glcd_command_write( MKT_KS0108_ADDRESS + new_address );
            #endif
         }   
         
         INLINE void mkt_glcd_address_increment( void ){
            #if mkt_glcd_remember_address != 0
               mkt_glcd_current_address++;   
            #endif
         }
         
         IN_RAM void mkt_glcd_data_write( int data ){
           
            #if mkt_glcd_use_buffer == 1
               mkt_glcd_buffer[ mkt_glcd_save_index ] = data;
            #endif 
         
            // select data
            mkt_fixed_pin_write( mkt_glcd_di, 1 );
         
            // do the write
            mkt_glcd_write( data );
            
            // the chip has incremented the address
            mkt_glcd_address_increment();   
         }
         
         #if mkt_glcd_use_buffer == 1
            int mkt_real_glcd_data_read( void ){
           
               int x = 0;
            
               // the chip will increment the address
               mkt_glcd_address_increment();   
            
               mkt_fixed_pin_write( mkt_glcd_e, 0 );
               
               // select read
               mkt_fixed_pin_write( mkt_glcd_rw, 1 );
            
               // select data
               mkt_fixed_pin_write( mkt_glcd_di, 1 );
            
               // switch to input
               mkt_glcd_direction( mkt_input );
            
               // reading must occur while E is high
               mkt_fixed_pin_write( mkt_glcd_e, 1 );
               mkt_wait_us( 1 );
            
               if( mkt_fixed_pin_read( mkt_glcd_d0 )){ x |= ( 1 << 0 ); }
               if( mkt_fixed_pin_read( mkt_glcd_d1 )){ x |= ( 1 << 1 ); }
               if( mkt_fixed_pin_read( mkt_glcd_d2 )){ x |= ( 1 << 2 ); }
               if( mkt_fixed_pin_read( mkt_glcd_d3 )){ x |= ( 1 << 3 ); }
               if( mkt_fixed_pin_read( mkt_glcd_d4 )){ x |= ( 1 << 4 ); }
               if( mkt_fixed_pin_read( mkt_glcd_d5 )){ x |= ( 1 << 5 ); }
               if( mkt_fixed_pin_read( mkt_glcd_d6 )){ x |= ( 1 << 6 ); }
               if( mkt_fixed_pin_read( mkt_glcd_d7 )){ x |= ( 1 << 7 ); }
            
               // make E low again to end the read operation
               mkt_fixed_pin_write( mkt_glcd_e, 0 );
               mkt_wait_us( 1 );   
            
               return x;
               
            }
         #endif
         
         INLINE int mkt_glcd_data_read( void ){
            #if mkt_glcd_use_buffer == 1
               return mkt_glcd_buffer[ mkt_glcd_save_index ];
            #else             
               (void) mkt_real_glcd_data_read();
               return mkt_real_glcd_data_read();
            #endif
         }
         
         void mkt_glcd_init( void ){
         
            int i;
           
            mkt_pin_configure( 19, mkt_output );
            mkt_fixed_pin_write( 19, 1 );
            mkt_wait_us( 100 * 1000 );
            mkt_fixed_pin_write( 19, 0 );
            mkt_wait_us( 100 * 1000 );
           
            // CS1, CS2, RW, DI, E as outputs
            mkt_pin_configure( mkt_glcd_cs1, mkt_output );
            mkt_pin_configure( mkt_glcd_cs2, mkt_output );
            mkt_pin_configure( mkt_glcd_di,  mkt_output );
            mkt_pin_configure( mkt_glcd_e,   mkt_output );
            #ifdef mkt_glcd_rw
               mkt_pin_configure( mkt_glcd_rw,  mkt_output );
            #endif
            
            // write, so we can make the data pins outputs
            #ifdef mkt_glcd_rw
               mkt_fixed_pin_write( mkt_glcd_rw, 0 );
            #endif
         
            // data lines output (for now)
            mkt_pin_configure( mkt_glcd_d0, mkt_output );
            mkt_pin_configure( mkt_glcd_d1, mkt_output );
            mkt_pin_configure( mkt_glcd_d2, mkt_output );
            mkt_pin_configure( mkt_glcd_d3, mkt_output );
            mkt_pin_configure( mkt_glcd_d4, mkt_output );
            mkt_pin_configure( mkt_glcd_d5, mkt_output );
            mkt_pin_configure( mkt_glcd_d6, mkt_output );
            mkt_pin_configure( mkt_glcd_d7, mkt_output );
           
           for (i=0;i<mkt_glcd_n_controllers;i++) {
               mkt_glcd_chip( i );
               mkt_glcd_command_write( MKT_KS0108_ON ); 
               mkt_glcd_command_write( MKT_KS0108_FIRST_LINE + 0 );
            }
         }
         
         void mkt_glcd_pixel_write( int x, int y, int mode ){
            int d;
            mkt_glcd_address( x, y );
            d = mkt_glcd_data_read();
            if( mode == mkt_set ){
               d |= 1 << ( y % 8 );
            } else if( mode == mkt_clear ){
               d &= ~ ( 1 << ( y % 8 ));
            } else if( mode == mkt_flip ){
               d ^= 1 << ( y % 8 );
            }
            #if mkt_glcd_use_buffer == 0
               mkt_glcd_address( x, y );
            #endif 
            mkt_glcd_data_write( d );
         }
         
         INLINE int int_min( int x, int y ){
            if( x < y) return x; else return y; }
               
         INLINE int int_max( int x, int y ){
            if( x > y) return x; else return y; }                                    
         
         IN_RAM void mkt_glcd_block_write( 
         
               // destination coordinates on LCD
            int gx, int gy,            
                 
               // x and y size of block to be copied
            int xbits, int ybits, 
            
               // source data block
            const unsigned char *data, 
            
               // x and y offset in the source data block
            int xstart, int ystart, 
            
               // stride of the source data in bytes
            int stride,
            
               // LCD wpixel write mode
            int mode
         ){
            int dx, dy;   // indexes within the copied block on the display
            int sx, sy;   // indexes within the source block, including offset
            int ddy, ssy; // temporary y indexes
            int nexty;    // next value for sy
            int a;        // bit 'address' within source data 
            int pixels;   // pixel byte retrieved from the source data
            int d;        // LCD data
            int mask;     // mask for writing the bit
            int ddymax;
            
            nexty = 0; // to silence a warning
            
            // chop to the display size
            xbits = int_min( xbits, gx + mkt_glcd_h );
            ybits = int_min( ybits, gy + mkt_glcd_v );
            
            // step through the y on the display 
            // (y first to minimize explicit address changes)
            // steps are to (vertical) byte boundaries
            // sy : source y address in bits
            // dy : destination y address in bits
            sy = ystart * stride * 8;
            for( dy = gy; dy < gy + ybits; dy = ( dy + 8 ) & (~7)){
             
               // step through the x on the display 
               sx = xstart;
               for( dx = gx; dx < gx + xbits; dx++ ){
                 
                  #if 0
                     print( "\\n===" );
                     print( "   sy=" );phex( sy );
                     print( "   dy=" );phex( dy );
                     print( "   sx=" );phex( sx );
                     print( "   dx=" );phex( dx );
                  #endif
         
                  // set the display address (adresses a bit)
                  mkt_glcd_address( dx, dy );
         
                  // read existing screen data (the byte that contains the bit)        
                  d = mkt_glcd_data_read();
                  #if 0 
                     print( "\\nread " );phex( d );
                     print( "  dx= " );phex( dx );
                     print( "  dy= " );phex( dy );
                  #endif
                  
                  // step up to 8 pixels in the y direction on the display,
                  // stepping up up to a byte boundary on the display
                  ssy = sy;
                  ddymax = int_min(( dy | 0x07) + 1, gy + ybits );
                  for( ddy = dy; ddy < ddymax; ddy++ ){          
                     a = ssy + sx;
                     pixels = data[ a / 8 ]; 
                     #if 0
                        print( "\\n" );
                        print( "   ddy=" );phex( ddy );
                        print( "   dy=" );phex( dy );
                        print( "   ssy=" );phex( ssy );
                        print( "   sx=" );phex( sx );
                        print( "   a=" );phex( a );
                        print( "   pixels=" );phex( pixels );
                     #endif
                     mask = ( 1 << ( ddy % 8 ));
                     if( pixels & ( 0x80 >> ( a % 8 ))){
                        if( mode == mkt_set ){
                           d |= mask;
                        } else if( mode == mkt_clear ){
                           d &= ~ mask;
                        } else if( mode == mkt_flip ){
                           d ^= mask;
                        } else if( mode == mkt_write ){
                           d |= mask;
                        }
                     } else {
                        if( mode == mkt_write ){
                           d &= ~ mask;
                        }
                     }
                     ssy += stride * 8;
                     nexty = ssy;
                  }          
                 
                  // write the byte back
                  //print( "    write " );phex( d );
                  #if mkt_glcd_use_buffer == 0
                     mkt_glcd_address( x, y );
                  #endif 
                  mkt_glcd_data_write( d );
                  
                  // mkt_wait_us( 1000 * 1000 );
                  
                  // next step in x direction in the source data
                  sx++;         
               }
               
               // next step in y direction in the source data
               sy = nexty;
            }
         }   
         
         void mkt_glcd_clear( void ){
            int x,y;
            for( y = 0; y < 8; y++ ){
               for( x = 0; x < 128; x++ ){
                  mkt_glcd_address( x, 8 * y );
                  mkt_glcd_data_write( 0 );
               }
            }  
            if(0) for( y = 0; y < 64; y++ ){
               for( x = 0; x < 128; x++ ){
                  mkt_glcd_address( x, y );
                  mkt_glcd_data_write( 0 );
               }
            }  
         }             
      """.replace( "INLINE", Always_Inline ).replace( "IN_RAM", In_RAM ))
      
      
   ##########################################################################
   #
   # Graphic LCD - T6369
   #
   ##########################################################################
         
   def Graphic_LCD_T6963( self ):   
      GLCD_Type = self.Configuration.Get_Value( mkt_glcd_type, None )
      if GLCD_Type != mkt_t6963:
         return
        
      self.Configuration.Extrapolate( "glcd_d%d", 7 )  
      
      self.Documentation( """
                  
            To configure a graphics LCD you must specify the controller
            and the ARM pins the controller is connected to. 
            The example below shows a configuration for a T6963 controller,
            which is the only one supported at this moment.
            
            #literal
               #configure   MK_GLCD_TYPE     MK_GLCD_T6963
               #configure   MK_GLCD_PIXELS_X           240
               #configure   MK_GLCD_PIXELS_Y           128
               #configure   MK_GLCD_CHAR_WIDTH           6
                     
               #configure   MK_GLCD_PIN_WD               9
               #configure   MK_GLCD_PIN_RD              10
               #configure   MK_GLCD_PIN_CE              11
               #configure   MK_GLCD_PIN_CD              12
               #configure   MK_GLCD_PIN_RST             13      
               #configure   MK_GLCD_PIN_FS              14
               
               #configure   MK_GLCD_PIN_D0              15
               #configure   MK_GLCD_PIN_D1              16
               #configure   MK_GLCD_PIN_D2              17
               #configure   MK_GLCD_PIN_D3              18
               #configure   MK_GLCD_PIN_D4              19
               #configure   MK_GLCD_PIN_D5              20
               #configure   MK_GLCD_PIN_D6              21
               #configure   MK_GLCD_PIN_D7              22
            #end literal
            
            You must specify the LCD controller and the number of pixels in X and
            Y direction. You can specify the character width, which can be either
            6 or 8. The default, when the configuration of MK_GLCD_CHAR_WIDTH is 
            omitted, is 6.
            
            You must specify the ARM pins that are connected to the controller's
            control lines. The WD, RD and CD lines are mandatory.
            
            The configuration of the MK_GLCD_PIN_CE pin is optional: when
            omitted it is not used, the CE pin of the controller can
            be permanently tied to active (== low). Note that this rules out the
            sharing of for instance the data pins with other peripherals.
            
            The configuration of the MK_GLCD_PIN_RST is also optional: when
            omitted it is not used. In that case the RST of the controller should be 
            connected to an appropriate reset circuit, and the application must make 
            sure to wait for this circuit to release the controller from reset before
            it attempts to initialise the LCD. Tying the RST pin of the controller
            permanently high might also work, depending on the rise time of the power
            supply.
            
            The configuration of MK_GLCD_PIN_FS is also optional: when omitted
            the FS pin of the controller must be tied high or low, corresponding
            to the configured character width.
         
            The configurations of MK_GLCD_PIN_D1 ... MK_GLCD_PIN_D7 are also
            optional: when MK_GLCD_PIN_D1 is missing it is assumed to be at 
            ( MK_GLCD_PIN_D0 + 1 ), etc. The interface to the LCD will be quicker
            (use less CPU time) when the data pins are consequtive and all within
            the same set of 32 pins.  
      
      
         #article graphic-lcd  
            #header mkt_t6963_command_write
            
            #interface mkt_t6963_command_write
               writes a command byte to the T6963 controller
               #parameter R0 cmd unsigned char
                  the command byte
            
            The function mkt_t6963_command_write write the command byte cmd
            to the T6963 LCD controller.
            
            This function is available when MK_GLCD_TYPE is 
            configured as mkt_t6963.
         
         #section headers
            #if MK_GLCD_TYPE == mkt_t6963
               #ifndef __ASSEMBLER__
                  void mkt_t6963_command_write( unsigned char cmd );
               #endif   
            #endif 
      """ )
         
      self.C_Header( """             
         void mkt_t6963_command_write( unsigned char cmd ){
            mkt_t6963_command_data_write( c, true );
         } 
      """ )
         
      self.Documentation( """                        
         #article graphic-lcd  
            #header mkt_t6963_data_write
            
            #interface mkt_t6963_command_write
               writes a data byte to the T6963 controller
               #parameter R0 d unsigned char
                  the data byte
            
            The function mkt_t6963_command_write write the data byte d
            to the T6963 LCD controller.
            
            This function is available when MK_GLCD_TYPE is 
            configured as mkt_t6963.
      
         
      """ )
      
      self.C( """  
         void mkt_t6963_command_write( unsigned char c ){
            mkt_t6963_command_data_write( d, false );
         }
      """ )
         
      self.Documentation( """                        
         #article graphic-lcd  
            #header MK_GLCD_xy_char_write
            
            #interface MK_GLCD_xy_char_write
               writes a char at (x,y)
               #parameter R0 x unsigned int
                  the x coordinate
               #parameter R1 y unsigned int
                  the y coordinate
               #parameter R2 chr unsigned char
                  the char to write
            
            The function MK_GLCD_xy_char_write writes the character chr
            at the position (x,y). 
            (0,0) is the top-left corner of the display.
         
      """ )
         
      self.C_Header( """             
            void mkt_t6963_xy_char_write( 
               unsigned int x,
               unsigned int y, 
               unsigned char chr 
            );
      """ )
         
      self.C( """
         void void mkt_t6963_xy_char_write( 
               unsigned int x,
               unsigned int y, 
               unsigned char chr 
         ){
            mkt_t6963_command_and_address_write( 
               mkt_t6963_SET_ADDRESS_POINTER, 
               ( y * MK_GLCD_NCHAR_X ) + x 
            );
            mkt_t6963_data_write( c - 0x20 );
            mkt_t6963_command_write( mkt_t6963_DATA_WRITE_AND_NONVARIALBE );
         }          
      """ )
         
      self.Documentation( """                        
         #article graphic-lcd  
            #header MK_GLCD_xy_pixel_write
            
            #interface MK_GLCD_xy_pixel_write
               writes a a pixel at (x,y)
               #parameter R0 x unsigned int
                  the x coordinate
               #parameter R1 y unsigned int
                  the y coordinate
               #parameter R2 pixel bool
                  the pixel (on or off)
            
            The function MK_GLCD_xy_pixel_write writes a single pixel
            at the position (x,y). 
            (0,0) is the top-left corner of the display.
            The parameter bool determines whether the pixel is set 
            (bool == true) or cleared (bool == false).
         
      """ )
         
      self.C_Header( """             
         void MK_GLCD_xy_pixel_write( 
            unsigned int x, 
            unsigned int y, 
            bool pixel 
         );
      """ )
         
      self.C( """
               void MK_GLCD_xy_pixel_write( 
                  unsigned int x, 
                  unsigned int y, 
                  bool pixel 
               ){
                  mkt_t6963_command_and_address_write( 
                     mkt_t6963_SET_ADDRESS_POINTER, 
                     mkt_t6963_GRAPHICS_BASE 
                     + (( MK_GLCD_PIXELS_X / MK_GLCD_CHAR_WIDTH ) * y ) 
                     + ( x / MK_GLCD_CHAR_WIDTH )
                  );
                  mkt_t6963_command_write( 
                     ( pixel ? 0xFF : 0xF7 ) +
                     (( MK_GLCD_CHAR_WIDTH == 8 ? 0 : -2 )
                     - ( x % MK_GLCD_CHAR_WIDTH )));
               } 
            #endif
            
      """ )
         
      self.Documentation( """                        
         #article graphic-lcd  
            #header mkt_t6963_LCD_text_clear
            
            #interface mkt_t6963_LCD_text_clear
               clear the text pane of a T6963 LCD
            
            The function mkt_t6963_LCD_text_clear clears the
            text pane of an LCD display with a T6963 controller.
            
            This function is available when MK_GLCD_TYPE is 
            configured as mkt_t6963.
         
      """ )
         
      self.C_Header( """             
                  void mkt_t6963_LCD_text_clear( void );
      """ )
         
      self.C( """

               unsigned int _MK_GLCD_x, _MK_GLCD_y;
         
               void mkt_t6963_LCD_text_clear( void ){
                  int x, y;
                  for( x = 0; x < MK_GLCD_NCHAR_X; x++ ){
                     for( y = 0; y < MK_GLCD_NCHAR_Y; y++ ){
                        MK_GLCD_xy_char_write( x, y, ' ' );
                     }
                  }      
                  _MK_GLCD_x = 0;
                  _MK_GLCD_y = 0;
               }
            #endif
            
      """ )
         
      self.Documentation( """                        
         #article graphic-lcd  
            #header mkt_t6963_LCD_graphics_clear
            
            #interface mkt_t6963_LCD_graphics_clear
               clear the graphics pane of a T6963 LCD
            
            The function mkt_t6963_LCD_graphics_clear clears the
            graphics pane of an LCD display with a T6963 controller.
            
            This function is available when MK_GLCD_TYPE is 
            configured as mkt_t6963.
         
      """ )
         
      self.C_Header( """             
                  mkt_t6963_LCD_graphics_clear( void );
      """ )
         
      self.C( """

               void mkt_t6963_LCD_graphics_clear( void ){
                  int a;
                  for( 
                     a = 0; 
                     a < (( MK_GLCD_PIXELS_X / MK_GLCD_CHAR_WIDTH ) 
                        * MK_GLCD_PIXELS_Y ); 
                     a++ 
                  ){
                     mkt_t6963_command_and_address_write( 
                        mkt_t6963_SET_ADDRESS_POINTER, 
                        mkt_t6963_GRAPHICS_BASE + a
                     );
                     mkt_t6963_data_write( 0x00 );
                     mkt_t6963_command_write( mkt_t6963_DATA_WRITE_AND_NONVARIALBE );
                  }
               }
            #endif
         
      """ )
         
      self.Documentation( """                        
         #article graphic-lcd  
            #header MK_GLCD_clear
            
            #interface MK_GLCD_clear
               clear a graphics LCD
            
            The function MK_GLCD_clear clears a graphics LCD.
         
      """ )
         
      self.C_Header( """             
                  MK_GLCD_clear( void );
      """ )
         
      self.C( """

               void MK_GLCD_clear( void ){
                  mkt_t6963_LCD_text_clear();
                  mkt_t6963_LCD_graphics_clear(); 
               }
            #endif
            
      """ )
         
      self.Documentation( """                        
         #article graphic-lcd  
            #header MK_GLCD_char_put
            
            #interface MK_GLCD_char_put
               writes a character
               #parameter R0 chr unsigned char
                  the char to write
            
            The function MK_GLCD_char_put writes a single character to a graphic LCD
            and advances the (invisible) write cursor one position to the right.
            When the write cursor is outside the visible part of the LCD
            this function has no effect.
            
            The following characters have a special meaning: 
            
            #list
               '\n' : puts the write cursor at the start of the next line.
               
               '\r' : puts the write cursor at the start of the current line.
            
               '\v' : clears the display and puts the cursor at the 
               top-left position (same effect as calling MK_GLCD_clear()).
               
            #end list   
         
      """ )
         
      self.C_Header( """             
                  MK_GLCD_char_put( char chr );
      """ )
         
      self.C( """

               void MK_GLCD_char_put( char chr ){
                  if( chr == '\n' ){
                     _MK_GLCD_x = 0;
                     _MK_GLCD_y++;
                     return;
                  }
                  if( chr == '\r' ){
                     _MK_GLCD_x = 0;
                     return;
                  }
                  if( chr == '\v' ){
                     mkt_t6963_LCD_text_clear();
                     return;
                  } 
                  if( 
                     ( _MK_GLCD_x < MK_GLCD_NCHAR_X )
                     && ( _MK_GLCD_y < MK_GLCD_NCHAR_Y )
                  ){
                     MK_GLCD_xy_char_write( 
                        _MK_GLCD_x, 
                        _MK_GLCD_y,
                        chr
                     );
                     _MK_GLCD_x++;
                  }   
               }
            #endif
               
         #article graphic-lcd  
            #header MK_GLCD_init
            
            #interface MK_GLCD_init
               initialsie a graphics LCD
            
            The function MK_GLCD_init initialises a graphics LCD.
         
      """ )
         
      self.C_Header( """             
                  MK_GLCD_init( void );
      """ )
         
      self.C( """

               void mkt_t6963_wait( void ){
                  int not_ready = 1;
               
                  MK_GPIO_direction( MK_GR_LCD_PIN_D0,  MK_GPIO_INPUT );
                  MK_GPIO_direction( MK_GR_LCD_PIN_D1,  MK_GPIO_INPUT );
                  MK_GPIO_direction( MK_GR_LCD_PIN_D2,  MK_GPIO_INPUT );
                  MK_GPIO_direction( MK_GR_LCD_PIN_D3,  MK_GPIO_INPUT );
                  MK_GPIO_direction( MK_GR_LCD_PIN_D4,  MK_GPIO_INPUT );
                  MK_GPIO_direction( MK_GR_LCD_PIN_D5,  MK_GPIO_INPUT );
                  MK_GPIO_direction( MK_GR_LCD_PIN_D6,  MK_GPIO_INPUT );
                  MK_GPIO_direction( MK_GR_LCD_PIN_D7,  MK_GPIO_INPUT );
                  
                  while( not_ready ){
                  
                     MK_GPIO_write( MK_GR_LCD_PIN_CD, true );
                     MK_GPIO_write( MK_GR_LCD_PIN_RD, false );
                     MK_GPIO_write( MK_GR_LCD_PIN_CE, false );         
                     
                     // MK_wait_us( 1 ); 
                     
                     if( 
                        ( MK_GPIO_read( MK_GR_LCD_PIN_D0 ))
                        && ( MK_GPIO_read( MK_GR_LCD_PIN_D1 ))
                     ){
                        not_ready = 0;
                     }
                     
                     MK_GPIO_write( MK_GR_LCD_PIN_RD, true );
                     MK_GPIO_write( MK_GR_LCD_PIN_CE, true );         
         
                     // MK_wait_us( 1 ); 
                  }   
               }   
            
               void MK_GLCD_init( void ){
               
                  // reset low (== LCD in reset)
                  MK_GPIO_write( MK_GLCD_PIN_RST, false );   
                  MK_GPIO_direction( MK_GLCD_PIN_RST, MK_GPIO_OUTPUT );
         
                  // CE high (== LCD active)
                  MK_GPIO_write( MK_GLCD_PIN_CE, true );
                  
                  // control lines must be outputs
                  MK_GPIO_direction( MK_GLCD_PIN_WD,  MK_GPIO_OUTPUT );
                  MK_GPIO_direction( MK_GLCD_PIN_RD,  MK_GPIO_OUTPUT );
                  MK_GPIO_direction( MK_GLCD_PIN_CE,  MK_GPIO_OUTPUT );
                  MK_GPIO_direction( MK_GLCD_PIN_CD,  MK_GPIO_OUTPUT );
                  
                  // select font
                  #ifdef MK_GLCD_PIN_FS
                     MK_GPIO_direction( MK_GLCD_PIN_FS,  MK_GPIO_OUTPUT );
                     MK_GPIO_write( MK_GLCD_PIN_FS, MK_GLCD_CHAR_WIDTH == 6 );
                  #endif
                  
                  // 1 ms for the chip to reset
                  MK_wait_us( 1000 );
                  MK_GPIO_write( MK_GLCD_PIN_RST, true );   
                  
                  // 1 ms to recover from reset
                  MK_wait_us( 1000 );
                  
                  mkt_t6963_command_and_address_write( 0x40, mkt_t6963_TEXT_BASE );
                  mkt_t6963_command_and_address_write( 0x41, MK_GLCD_NCHAR_X );
                  mkt_t6963_command_and_address_write( 0x42, mkt_t6963_GRAPHICS_BASE );
                  mkt_t6963_command_and_address_write( 0x43, MK_GLCD_NCHAR_X );
                  mkt_t6963_command_write( 0x80 ); // OR mode
                  mkt_t6963_command_write( 0x9C ); // text and graphics on, no cursor
               }
            #endif
               
      """ )
         
      self.Documentation( """                        
         #article graphic-lcd  
            #header MK_GLCD
            
            The function MK_GLCD_init initialises a graphics LCD.
         
         #section headers
            #define MK_GLCD_T6963 1056
            
            #ifdef MK_GLCD_TYPE
               
               #if MK_GLCD_TYPE == MK_GLCD_T6963
                  #define MK_GLCD_TYPE_OK
               #endif
               
               #ifndef MK_GLCD_TYPE_OK
                  #error "invalid MK_GLCD_TYPE configured"
               #endif         
               #ifndef MK_GLCD_PIXELS_X  
                  #error "no MK_GLCD_PIXELS_X configured"
               #endif   
               #infdef MK_GLCD_PIXELS_Y 
                  #error "no MK_GLCD_PIXELS_Y configured"
               #endif   
               
               #ifndef MK_GLCD_CHAR_WIDTH
                  #define MK_GLCD_CHAR_WIDTH 6
               #endif
               #ifndef MK_GLCD_CHAR_HEIGHT
                  #define MK_GLCD_CHAR_HEIGHT 8
               #endif
               
               #define MK_GLCD_NCHAR_X ( MK_GLCD_PIXELS_X / MK_GLCD_CHAR_WIDTH )
               #define MK_GLCD_NCHAR_Y ( MK_GLCD_PIXELS_Y / MK_GLCD_CHAR_HEIGHT )
                  
               #if MK_GLCD_TYPE == MK_GLCD_T6963
                  #if ( MK_GLCD_CHAR_WIDTH != 6 ) && ( MK_GLCD_CHAR_WIDTH != 8 )
                     #error "invalid MK_GLCD_CHAR_WIDTH configured"
                  #endif      
                  
                  #if MK_GLCD_CHAR_HEIGHT != 8
                     #error "invalid MK_GLCD_CHAR_HEIGHT configured"
                  #endif    
         
                  #define mkt_t6963_SET_CURSOR_POINTER         0x21
                  #define mkt_t6963_SET_OFFSET_REGISTER         0x22
                  #define mkt_t6963_SET_ADDRESS_POINTER         0x24
            
                  #define mkt_t6963_SET_TEXT_HOME_ADDRESS         0x40
                  #define mkt_t6963_SET_TEXT_AREA               0x41
                  #define mkt_t6963_SET_GRAPHIC_HOME_ADDRESS      0x42
                  #define mkt_t6963_SET_GRAPHIC_AREA            0x43
            
                  #define mkt_t6963_MODE_SET                  0x80
            
            
                  #define mkt_t6963_DISPLAY_MODE               0x90
                     #define mkt_t6963_CURSOR_BLINK_ON         0x01
                     #define mkt_t6963_CURSOR_DISPLAY_ON         0x02
                     #define mkt_t6963_TEXT_DISPLAY_ON         0x04
                     #define mkt_t6963_GRAPHIC_DISPLAY_ON      0x08            
            
            
                  #define mkt_t6963_CURSOR_PATTERN_SELECT         0xA0
                     #define mkt_t6963_CURSOR_1_LINE            0x00
                     #define mkt_t6963_CURSOR_2_LINE            0x01
                     #define mkt_t6963_CURSOR_3_LINE            0x02
                     #define mkt_t6963_CURSOR_4_LINE            0x03
                     #define mkt_t6963_CURSOR_5_LINE            0x04
                     #define mkt_t6963_CURSOR_6_LINE            0x05
                     #define mkt_t6963_CURSOR_7_LINE            0x06
                     #define mkt_t6963_CURSOR_8_LINE            0x07
            
                  #define mkt_t6963_SET_DATA_AUTO_WRITE         0xB0
                  #define mkt_t6963_SET_DATA_AUTO_READ         0xB1
                  #define mkt_t6963_AUTO_RESET               0xB2
            
                  #define mkt_t6963_DATA_WRITE_AND_INCREMENT      0xC0
                  #define mkt_t6963_DATA_READ_AND_INCREMENT      0xC1
                  #define mkt_t6963_DATA_WRITE_AND_DECREMENT      0xC2
                  #define mkt_t6963_DATA_READ_AND_DECREMENT      0xC3
                  #define mkt_t6963_DATA_WRITE_AND_NONVARIALBE   0xC4
                  #define mkt_t6963_DATA_READ_AND_NONVARIABLE      0xC5
            
                  #define mkt_t6963_SCREEN_PEEK               0xE0
                  #define mkt_t6963_SCREEN_COPY               0xE8 
               
                  #define mkt_t6963_TEXT_BASE      0x0000
                  #define mkt_t6963_GRAPHICS_BASE  0x0400
               #endif
         
            #endif    
         
         
         #section headers
         
            #define MK_GLCD_T6963 1056
            
            #ifdef MK_GLCD_TYPE
            
               #ifndef MK_GLCD_PIN_WD
                  #error "MK_GLCD_TYPE configured but no MK_GLCD_PIN_WD"
               #endif
         
               #ifndef MK_GLCD_PIN_RD
                  #error "MK_GLCD_TYPE configured but no MK_GLCD_PIN_RD"
               #endif
               
               // MK_GLCD_PIN_CE is optional
         
               #ifndef MK_GLCD_PIN_CD
                  #error "MK_GLCD_TYPE configured but no MK_GLCD_PIN_CD"
               #endif
               
               //MK_GLCD_PIN_FS is optional
         
               //MK_GLCD_PIN_RST is optional
         
               #ifndef MK_GLCD_PIN_D0
                  #error "MK_GLCD_TYPE configured but no MK_GLCD_PIN_D0"
               #endif
         
               #ifdef MK_GLCD_PIN_D0
                  #ifndef MK_GLCD_PIN_D1
                     #define MK_GLCD_PIN_D1 (MK_GLCD_PIN_D0 + 1)
                  #endif
                  #ifndef MK_GLCD_PIN_D2
                     #define MK_GLCD_PIN_D2 (MK_GLCD_PIN_D1 + 1)
                  #endif
                  #ifndef MK_GLCD_PIN_D3
                     #define MK_GLCD_PIN_D3 (MK_GLCD_PIN_D2 + 1)
                  #endif
                  #ifndef MK_GLCD_PIN_D4
                     #define MK_GLCD_PIN_D4 (MK_GLCD_PIN_D3 + 1)
                  #endif
                  #ifndef MK_GLCD_PIN_D5
                     #define MK_GLCD_PIN_D5 (MK_GLCD_PIN_D4 + 1)
                  #endif
                  #ifndef MK_GLCD_PIN_D6
                     #define MK_GLCD_PIN_D6 (MK_GLCD_PIN_D5 + 1)
                  #endif
                  #ifndef MK_GLCD_PIN_D7
                     #define MK_GLCD_PIN_D7 (MK_GLCD_PIN_D6 + 1)
                  #endif
               #endif
      """ )            
   
   ##########################################################################
   #
   # UART
   #
   ##########################################################################
   
   def UART( self ):
      self.Documentation( """   
         #article uart UARTs   
      
         A UART is a Universal Asynchronous Receiver and Transmitter. 
         It is a hardware implementation of the protocol used 
         for instance by the serial port of your PC.
         Most 32-bit microcontroller chips contain at least one UART.
         The Library provides support for the basic UART operations: 
         you can initialise the UART,
         you can check whether the UART is busy transmitting, 
         you can submit a character
         for transmitting, you can check wether the UART has a (received)
         character available, and you can retreive a received character.         
         The UART routines do not implement any form of handshaking.
         
         Each UART routine takes as first parameter a pointer to a UART.
         For UARTs are identified by the library as UART0, UART1, etc.
         
         The example below transmits a message each second at
         9600 baud using UART0. 
         
         Note that the routine 
         #link mkt_uart_char_write 
         requires a UART 
         parameter (besides the char which is to be transmitted), 
         hence to use 
         #link mkt_string_write, 
         a wrapper function must be 
         declared that is hard-coded for UART0, 
         and takes just a char as parameter.
   
         #code
            void print( char *s ){
               while( *s ){
                  mkt_uart_char_write( UART0, *s++ );
               }
            }
            
            int main( void ){
               mkt_uart_init( UART0, 9600 );
               while(1){
                  print( "Hello world\\n" )
                  mkt_wait_us( 1000 * 1000 );
                  print( "How do you do?\\n" )
                  mkt_wait_us( 1000 * 1000 );
               }
               return 0;
            }
         #end code
      """ )
            
      self.Documentation( """   
         #article uart
         #header mkt_uart_init
         
         #interface mkt_uart_init
            initialises the UART
            #parameter R0 UART UART_struct *
               pointer to the UART registers
            #parameter R1 baudrate unsigned int
               baudrate to be used
         
         The function mkt_uart_init initialises the UART for the indicated
         baudrate and connects the UARTs RxD and TxD functions to
         the designated I/O pin. The UART will be initialised
         for 8 databits, 1 stop bit, no partity, no handshaking.
         
         Note: this will disable the GPIO function on the Rx and Tx pins. 
         Check the datasheet of your chip for 
         the I/O pins designated for each UART.         
      """ )
         
      self.Assembler_And_C_Header( """    
         #define UART0 U0
         #define UART1 U1
      """ )   
      
      self.C_Header( """    
         void mkt_uart_init( UART uart, unsigned int baudrate );
      """ )   
      
      self.C( """    
         #define EA_PCLK ( mkt_cclk / 4 )
         void mkt_uart_init( UART uart, unsigned int baudrate ){
            int divider;
                    
            // set baudrate
            uart->LCR = 0x80;  // select DLL and DLM
            divider = EA_PCLK / ( 16 * baudrate );
            uart->DLM = divider / 256;
            uart->DLL = divider % 256;
         
            uart->LCR = 0x03; // select RBR and THR; select 8/N/1
            #ifdef U0TER
               uart->TER = 0x800; // enable Tx
            #endif
         
            // conect the appropriate pins to the UART
            if( uart == U0 ){
               mkt_pin_connect( 0, 1 );
               mkt_pin_connect( 1, 1 );
            }
            if( uart == U1 ){
               mkt_pin_connect( 8, 1 );
               mkt_pin_connect( 9, 1 );
            }
         }
      """ )   
      
      self.Documentation( """    
         #article uart
         #header mkt_uart_transmit_busy
         
         #interface mkt_uart_transmit_busy
            initialises the UART
            #parameter R0 UART UART_struct *
               pointer to the UART registers
            #result R0 busy bool
               true iff the UART is busy
         
         The function mkt_uart_transmit_busy reports whether
         the UART is currently transmitting a character. 
         
         Two situations where you might need this function are:         
         #list
         
         You want to call
         #link mkt_uart_char_write,
         but you can not tolerate any busy waiting within that
         function. In this case you will have to check 
         mkt_uart_transmit_busy first, and if it reports true
         you should not yet call mkt_uart_char_write.
                           
         You use an external transceiver that needs to be switched 
         from transmit to receive. After sending the last character
         you must poll mkt_uart_transmit_busy untill it returns
         false, and then you can switch the transceiver to receive.        
      """ )   
      
      self.C_Header( """    
         #ifndef __cplusplus 
            #define bool unsigned char
         #endif
         bool mkt_uart_transmit_busy( UART uart );
      """ )   
      
      self.C( """    
         bool mkt_uart_transmit_busy( UART uart ){
            return ( uart->LSR & 0x20 ) == 0;
         }
      """ )   
      
      self.Documentation( """        
         #article uart
         #header mkt_uart_char_write
         
         #interface mkt_uart_char_write
            sends a char 
            #parameter R0 UART UART_struct *
               pointer to the UART registers
            #parameter R1 chr char
               the char to be sent
         
         The function mkt_uart_char_write sends the char using the UART.
         This function first waits for the UART to complete transmitting
         of a previous character. When you can not tolerate this delay
         you can call 
         #link mkt_uart_transmit_busy:
         If that function returns false the mkt_uart_char_write
         will not incur any extra delay.
      """ )   
      
      self.C_Header( """    
         void mkt_uart_char_write( UART uart, char chr );
      """ )   
      
      self.C( """          
         void mkt_uart_char_write( UART uart, char chr ){
            while( ( uart->LSR & 0x20 ) == 0 ){}
            uart->THR = chr;
         }
      """ )   
      
      self.Documentation( """             
         #article uart
         #header mkt_uart_char_available
         
         #interface mkt_uart_char_available
            reports whether a received char is available
            #parameter R0 UART UART_struct *
               pointer to the UART registers
            #result R0 available bool
               true iff a char is available
               
         The function mkt_uart_char_available reports whether
         the UART currently has a received character available
         for retrieving using
         #link mkt_uart_char_get.
         If you want to read a character from the UART but you can
         not afford to wait for it (if no character is available
         mkt_uart_char_get will wait for one) you can first call  
         mkt_uart_char_available to avoid waiting.
            
      """ )   
      
      self.C_Header( """    
         bool mkt_uart_char_available( UART uart );
      """ )   
      
      self.C( """    
            bool mkt_uart_char_available( UART uart ){
               return ( uart->LSR & 0x01 ) != 0;
            }
      """ )   
      
      self.Documentation( """    
         #article uart
         #header mkt_uart_char_get
         
         #interface mkt_uart_char_get
            returns a received character
            #parameter R0 UART UART_struct *
               pointer to the UART registers
            #result R0 chr char
               the received char
               
         The function mkt_uart_char_get returns a received character.
         If no character is available it will wait untill one is.
         The function 
         #link mkt_uart_char_available
         can be used to test whether a character is available.
            
      """ )   
      
      self.C_Header( """    
         char mkt_uart_char_get( UART uart );
      """ )   
      
      self.C( """       
         char mkt_uart_char_get( UART uart ){
            while( ( uart->LSR & 0x01 ) == 0 ){}
            return (char) uart->RBR;
         }
      """ )
      
   def Format( self ):
      return
      self.Documentation( """      

      //===========================================================================
      //
      // Formatted character output routines
      //
      //===========================================================================
      
      #article char-format Formatted character output
         
         The formatted output routines are used to format data 
         and write it to a character output. 
         The mkt_f_* functions take a function as first parameter,
         which is called to write each character. 
         The mkt_* functions call the function pointed to by 
         the global 
         #link mkt_char_write 
         pointer to write each character.
         The user is responsible for setting this pointer before any such
         function is called.
         
         There are functions to write a character string, a number in binary, 
         hexadecimal or decimal format, and to dump a memory area. 
                         
         The available functions are:
         #list
            #link mkt_string_write mkt_string_write,
            #link mkt_f_string_write mkt_f_string_write
            
            #link mkt_bin_write,
            #link mkt_f_bin_write
            
            #link mkt_decimal_write,
            #link mkt_f_decimal_write
            
            #link mkt_hex_write,
            #link mkt_f_hex_write
            
            #link mkt_memory_write,
            #link mkt_f_memory_write
         #end list            
      """)
      
      self.Documentation( """      
         #article char-format 
         #header mkt_char_write
                
         The function pointed to by the global variable mkt_char_write is
         used by the mkt_* formatted charcter output functions to write
         each character. The user is responsible for having this pointer
         point to a suitable function.               
      """)
      
      self.C_Header( """      
         extern void (*mkt_char_write)( char );
      """)
      
      self.C( """         
         void (*mkt_char_write)( char ) = NULL;
      """)
      
      self.Documentation( """      
         #article char-format 
         #header mkt_string_write, mkt_f_string_write
         #anchor mkt_string_write 
         #anchor mkt_f_string_write 
         
         #interface mkt_f_string_write
            write the '\\0'-terminated string str to the write() function
            #parameter put (* write)(char)
               pointer to char put function
            #parameter str char *
               pointer to '\\0'-terminated string
         
         #interface mkt_string_write
            write the '\\0'-terminated string str to the 
            function pointed to by mkt_char_write
            #parameter str char *
               pointer to '\\0'-terminated string
         
         These functions write the '\\0'-terminated string pointed to by str,
         using either the write() function that is provided, or the function
         pointed to by 
         #link mkt_char_write.
         
         When str is a NULL pointer nothing will be written.
               
      """)
      
      self.C_Header( """      
         void /* "C" */ mkt_string_write( char *str );
         void /* "C" */ mkt_f_string_write( void put( char x ), char *str );
      """)
      
      self.C( """         
         // write the '\\0'-terminated string str to write()         
         void mkt_f_string_write( void write( char x ), char *str ){
            if( str == NULL ){ return; }
            while( *str != '\\0' ){
               write( *str++ );
            }
         }  
                
         /* idem, but use (*mkt_char_write)()                                                          
         void mkt_string_write( char *str ){
            mkt_f_string_write( mkt_char_write, str );
         }
      """)
      
      self.Documentation( """      
         #header mkt_bin_write, mkt_f_bin_write
         #anchor mkt_bin_write, mkt_f_bin_write
         
         #interface mkt_bin_write
            write to (*mkt_char_write)() n binary digits of the value x
            #parameter x int
               value to write
            #parameter n int
               number of digits to write
            #parameter sep char *
               separates groups of 8 digits
         
         #interface mkt_f_bin_write
            write to write() n binary digits of the value x
            #parameter write (* write)(char)
               pointer to char put function
            #parameter x int
               value to write
            #parameter n int
               number of digits to write
            #parameter sep char *
               separates groups of 8 digits
         
         This function uses the put function to output
         the n least-significant bits of the value x.
         For readability, each group of 4 bits is separated 
         by the string sep. For no sepearation you
         can pass either an empty string "" or a NULL pointer.
      """)
      
      self.C_Header( """      
            void /* "C" */ mkt_bin_write( 
               int x, int n, char *sep );
            void /* "C" */ mkt_f_bin_write( 
               void write( char x ), int x, int n, char *sep );
      """)
      
      self.C( """      
         /* write to write() the unsigned integer x, in n binary positions 
         /* leading zero's are not suppressed                            
         /* sep is inserted every 4 digits                               
         void mkt_f_bin_write( void write( char x ), int x, int n, char *sep ){
            int i = 0;
            while( true ){
               put( (( x >> ( --n )) & 0x01) ? '1' : '0' );
               if( n <= 0 ){
                  return;
               }
               if(( ++i % 4 ) == 0 ){
                  mkt_string_write( write, put, sep );
               }
            }
         }
      
         /* idem, but use (*mkt_char_write)()                                                          
         void mkt_bin_write( int x, int n, char *sep ){
            mkt_f_bin_write( mkt_char_write, x, n , sep );
         }
      """)
      
      self.Documentation( """      
         #article char-format 
         #header mkt_ch_decimal_write
         
         #interface mkt_ch_decimal_write
            write to put() n decimal digits of the value x
            #parameter R0 put (* put)(char)
               pointer to char put function
            #parameter R1 x int
               value to write
            #parameter R2 n int
               number of digits to write
         
         This function uses the put function to output
         the n least-significant decimal digits of the value x.
      """)
      
      self.C_Header( """      
            void /* "C" */ mkt_decimal_write( 
               int x, int n );
            void /* "C" */ mkt_f_decimal_write( 
               void put( char x ), int x, int n );
      """)
      
      self.C( """      
         void mkt_ch_decimal_write( int x, int n ){
            int p;
            if( n > 0 ){
               p = x % 10;
               mkt_ch_decimal_write( put, x / 10, n - 1 );
               put( '0' + p );
            }
         }
         
         /* idem, but use (*mkt_char_write)()                                                          
         void mkt_f_decimal_write( void put( char x ), int x, int n ){
            mkt_ch_decimal_write( mkt_char_write, x, n ); }
      """)
      
      self.Documentation( """      
         #article char-format 
         #header mkt_ch_hex_write
         
         #interface mkt_ch_hex_write
            write to put() n hexadecimal digits of the value x
            #parameter R0 put (* put)(char)
               pointer to char put function
            #parameter R1 x int
               value to write
            #parameter R2 n int
               number of digits to write
            #parameter R3 sep char *
               separates groups of 8 digits
         
         This function uses the put function to output
         the n least-significant hexadecimal digits of the value x.
         For readability, each group of 4 digits is separated 
         by the string sep. For no sepearation you
         can pass either an empty string "" or a NULL pointer.
      """)
      
      self.C_Header( """      
         void /* "C" */ mkt__hex_write( 
            int x, int n, char *sep );
         void /* "C" */ mkt_f_hex_write( 
            void put( char x ), int x, int n, char *sep );
      """)
      
      self.C( """      
      
            /* write to put() the unsigned integer x,                        */
            /* in n hexadecimal positions                                    */
            /* leading zero's are not suppressed                             */
            /* sep is inserted every 4 digits                                */
            void mkt_f_hex_write( void put( char x ), int x, int n, char *sep )
        
            /* write to put() the block of n bytes of memory starting at p   */

      
         void mkt_ch_hex_write( void put( char x ), int x, int n, char *sep ){
            int h, i = 0;
            while( true ){
               h = ( x >> ( --n * 4 )) & 0x0F;
               if( h >= 10 ){
                  h = ( h - 10 ) + 'A';
               } else {
                  h = h + '0';
               }
               put( h );
               if( n <= 0 ){
                  return;
               }
               if(( ++i % 4 ) == 0 ){
                  mkt_ch_string_write( put, sep );
               }
            }
         }
         
         /* idem, but use (*mkt_char_write)()                                                          
         void mkt_f_hex_write( int x, int n, char *sep ){
            mkt_ch_hex_write( mkt_char_write, x, n, sep ); }
      """)
      
      self.Documentation( """      
         #header mkt_ch_memory_write
         
         #interface mkt_ch_memory_write
            write to put() n bytes of memory staring at p
            #parameter R0 put (* put)(char)
               pointer to char put function
            #parameter R1 p void *
               pointer to the memory
            #parameter R2 n int
               number of bytes to dump
         
         This function uses the put function to output
         the values of n bytes starting at the memory address p.
      """)
      
      self.C_Header( """      
         void /* "C" */ mkt_memory_write( void put( char x ), void *p, int n );
         void /* "C" */ mkt_f_memory_write( void *p, int n );
      """)
      
      self.C( """      
         void mkt_f_memory_write( void put( char x ), void *p, int n ){
            unsigned char *x = p;
            int i = 0;
            mkt_ch_string_write( put, "\nmemory dump a=" );
            mkt_ch_hex_write( put, (unsigned int) p, 8, "-" );
            mkt_ch_string_write( put, " n=" );
            mkt_ch_hex_write( put, n, 4, 0 );
            while( n > i ){
               if (( i % 16 ) == 0 ){
                  put( '\n' );
               } else if (( i % 8 ) == 0 ){
                  mkt_ch_string_write( put, " - " );
               } else if( i > 0 ){
                  put( ' ' );
               }
               mkt_ch_hex_write( put, *x, 2, 0 );
               x++;
               i++;
            }
         }      
         void mkt_memory_write( void *p, int n ){
            mkt_f_memory_write( mkt_char_write, void *p, int n ){            
         }      
      """ )
         
#############################################################################
#
# Boards
#
#############################################################################

   def Boards( self ):
      self.Documentation( """
         #article boards Boards
         The following boards are supported:         
         #list         
            #paragraph #link hu_arm_v2     HU Armboard V2
            #paragraph #link hu_arm_v3     HU Armboard V3
            #paragraph #link hu_arm_v4     HU Armboard V4
            #paragraph #link keil_mcb2130  Keil MCB2130
            #paragraph #link olimex_p2148  Olimex P2148         
         #end list
      """ )
         
      self.Documentation( """
         #article boards Boards
         #header hu_arm_v2 HU Armboard V2
         
         #literal
            #configure board hu_armboard_v2
         #end literal
         
         When the 
         #link mkt_board board 
         is configured as hu_armboard_v2 MicroKit is configured 
         for Franc vd Bent's HU ARM board version 2:   
         
         #image board-hu-v2-3.jpg
         
         This board has
         
         #list
            #paragraph an NXP LPC2106 chip with a 10 MHz crystal
            #paragraph parallel-port wiggler hardware (DB25F connector)
            #paragraph an USB A (!) connector for power 
               (the data lines are not connected)
            #paragraph a DB9F serial connector for downloading 
               and communication (connected to the UART0 TxD and RxD pins)
            #paragraph two jumpers to enable 
               #link lpc-handshake-boot               
            #paragraph 8 LEDs (connected to an HC595 shift register)
            #paragraph a 1 line by 16 character LCD
            #paragraph a 16-key keypad (connected to two HC165 shift registers)
            #paragraph a small beeper/speaker
            #paragraph a 40-pin extension connector 
            #paragraph two jumpers to select RUN, JTAG, or bootload mode
         #end list
               
         More information about this board can be found on
         #url http://www.electronicengineering.nl/bent/ Franc's website  
         (select ARM environment; Dutch language only).
         
         When this board is specified the following defaults are active:
         
         #literal
            #configure chip          lpc2106
            #configure xtal          10 * MHz
            #configure cclk          60 * MHz
            #configure pclk          60 * MHz
            #configure link          wiggler
            #configure clcd_type     hd44780
            #configure clcd_lines    1
            #configure clcd_columns  16
            #configure clcd_rs       14
            #configure clcd_e        13
            #configure leds_n        8
            #configure leds_595_hq   2
            #configure leds_595_sq   4
            #configure leds_595_d    6
            #configure port          com1
            #configure baudrate      %s
         #end literal
         
         These defaults can be overruled by explicit definitions.
         As an example, one course on our school uses this board, 
         but with a two-line LCD instead of the standard one-line version. 
         The configuration used for this course is:
         
         #literal
            #configure board       mkt_hu_arm_v2 
            #configure clcd_lines  2
         #end literal   
         
         The board has two jumpers at the upper righthand side. The upper
         jumper (marked S1) controls whether bootload mode will be activated 
         at reset: top position (marked 2) for bootload mode. 
         The lower jumper (marked S2) controls whether the JTAG interface is
         enabled: top position (marked 1) enables the JTAG. 
         
         For JTAG operation both jumpers must be in their middle position
         (marked 1 for both jumpers),
         as indicated on the silkscreen in the lower left area. 
         
         For ROM downloading both jumpers must be in their top position
         (S1 in in position 2, S2 in position 1),
         and the reset key (bottom left) must be pressed.
         (When you forgot to press the reset you can in most cases press it
         when the download tool is trying to synchronise with the target.)
         The downloaded code will sometimes run after the download,
         but not always.
         
         To let the code in ROM run upon powerup or reset the jumpers 
         must be in the JTAG position: both in position 1.
      """ % Mkt_Serial_Baudrate )
   
      self.Documentation( """
         #article boards   
         #header hu_arm_v3 HU Armboard V3
      
         #literal
            #configure board hu_armboard_v3
         #end literal
         
         When the 
         #link mkt_board board 
         is configured as hu_armboard_v3 MicroKit is configured 
         for Franc vd Bent's HU ARM board version 3:   
         
         #image board-hu-v3-2.jpg
         
         This board has
         
         #list
            #paragraph an NXP LPC2148 chip 
               with 12 MHz and 32.768 crystals
            #paragraph parallel-port wiggler hardware (DB25F connector)
            #paragraph an USB connector for power;
               the data lines of this connector are connected 
               to the LPC2148 USB pins
            #paragraph a DB9F serial connector for downloading 
               and communication (connected to the UART0 TxD and RxD pins)
            #paragraph two jumpers to enable 
               #link lpc-handshake-boot               
            #paragraph 8 LEDs (connected to an HC595 shift register)
            #paragraph a 1 line by 16 character LCD
            #paragraph a 16-key keypad (via a PIC 16F630 microcontroller)
            #paragraph an SD-card connector
            #paragraph one 40-pin and two 8-pin extension connectors
            #paragraph two jumpers to select RUN, JTAG, or bootload mode (?)
         #end list
               
         More information about this board can be found on
         #url http://www.electronicengineering.nl/bent/ Franc's website  
         (select ARM environment; Dutch language only).
         
         When this board is specified the following defaults are active:
         
         #literal
            #configure chip          lpc2148
            #configure xtal          12 * MHz
            #configure cclk          60 * MHz
            #configure pclk          60 * MHz
            #configure link          wiggler
            #configure clcd_type     hd44780
            #configure clcd_lines    1
            #configure clcd_columns  16
            #configure clcd_rs       14
            #configure clcd_e        13
            #configure leds_n        8
            #configure leds_595_hq   16
            #configure leds_595_sq   4
            #configure leds_595_d    6
            #configure port          com1
            #configure baudrate      %s
         #end literal         
         
         These defaults can be overruled by explicit definitions.
   
         This board has two jumpers at the upper righthand side. The upper
         jumper (marked S1) controls whether bootload mode will be activated 
         at reset: top position (marked 2) for bootload mode. 
         The lower jumper (marked S2) controls whether the JTAG interface is
         enabled: top position (marked 1) enables the JTAG. 
         
         For JTAG operation both jumpers must be in their middle position
         (marked 1 for both jumpers),
         as indicated on the silkscreen in the lower left area. 
         
         For ROM downloading both jumpers must be in their top position
         (S1 in in position 2, S2 in position 1).
         The downloaded code will sometimes run after the download,
         but not always.
         
         To let the code in ROM run upon powerup or reset the jumpers 
         must be in the JTAG position: both in position 1.
       """ % Mkt_Serial_Baudrate )
   
      self.Documentation( """
         #article boards   
         #header hu_arm_v4 HU Armboard V4
      
         #literal
            #configure board hu_armboard_v4
         #end literal
         
         When the 
         #link mkt_board board 
         is configured as hu_armboard_v4 MicroKit is configured 
         for Franc vd Bent's HU ARM board version 4:  
      
         #image board-hu-v4-1.jpg
         
         This board has
         
         #list
            #paragraph an NXP LPC2148 chip 
               with 12 MHz and 32.768 crystals
            #paragraph an USB connector for debugging, serial communication 
               and serial downloading using an FT2232 interface chip
               (the serial interface is connected 
               to the UART0 TxD and RxD pins)
            #paragraph an USB connector for power;
               the data lines of this connector are connected 
               to the LPC2148 USB pins
            #paragraph a DB9F serial connector for downloading 
               and communication (connected to 
            #paragraph two jumpers to enable 
               #link lpc-handshake-boot               
            #paragraph 8 LEDs (connected to an HC595 shift register)
            #paragraph a 1 line by 16 character LCD
            #paragraph a 16-key keypad (via a PIC 16F630 microcontroller)
            #paragraph an SD-card connector
            #paragraph one 40-pin and two 8-pin extension connectors
            #paragraph two jumpers to select RUN, JTAG, or bootload mode (?)
         #end list
   
         More information about this board can be found on
         #url http://www.electronicengineering.nl/bent/ Franc's website  
         (select ARM environment; Dutch language only).
         
         When this board is specified the following defaults are active:
         
         #literal
            #configure chip          lpc2148
            #configure xtal          12 * MHz
            #configure cclk          60 * MHz
            #configure pclk          60 * MHz
            #configure link          ftdi2232
            #configure clcd_type     hd44780
            #configure clcd_lines    1
            #configure clcd_columns  16
            #configure clcd_rs       14
            #configure clcd_e        13
            #configure leds_n        8
            #configure leds_595_hq   16
            #configure leds_595_sq   4
            #configure leds_595_d    6
            #configure port          com4
            #configure baudrate      %s
         #end literal         
        
         These defaults can be overruled by an explicit configuration.
   
         This board has two jumpers at the upper righthand side. The upper
         jumper (marked S1) controls whether bootload mode will be activated 
         at reset: top position (marked 2) for bootload mode. 
         The lower jumper (marked S2) controls whether the JTAG interface is
         enabled: top position (marked 1) enables the JTAG. 
         
         For JTAG operation both jumpers must be in their middle position
         (marked 1 for both jumpers),
         as indicated on the silkscreen in the lower left area. 
         
         For ROM downloading both jumpers must be in their top position
         (S1 in in position 2, S2 in position 1).
         The downloaded code will sometimes run after the download,
         but not always.
         
         To let the code in ROM run upon powerup or reset the jumpers 
         must be in the JTAG position: both in position 1.
       """ % Mkt_FTDI_Baudrate )
      
      self.Documentation( """         
         #article boards   
         #header keil_mcb2130 KEIL MCB2130 board
         
         #literal
            #configure board keil_mcb2130
         #end literal
         
         When the 
         #link mkt_board board 
         is configured as keil_mcb MicroKit is configured 
         for the 
         #url http://www.keil.com Keil  
         #url http://www.keil.com/mcb2130 MCB2130        
         board:
      
         #image board-keil-mcb2130.jpg
                    
         This board has
         
         #list
            #paragraph an NXP LPC2148 chip 
               with 12 MHz and 32.768 kHz crystals
            #paragraph an USB connector for power 
               (the data pins are not connected) 
            #paragraph two DB9F serial connectors for downloading 
               and communication, connected to the two UARTs. The one
               connected to UART0 has the hardware for 
               #link lpc-handshake-boot  
               Two jumpers activate this hardware.            
            #paragraph 8 LEDs (connected to ARM pins via an 74LVC244 buffer)
            #paragraph a small loudspeaker 
               (connected to an ARM pin via an LM386 amplifier)
            #paragraph a trim potentiometer, connected to an ARM A/D pin
            #paragraph a reset button and a button that is connected
               to a reset pin
            #paragraph a connector for a wall-wart (5V DC)
            #paragraph an ARM-standard 20-pin JTAG connector
            #paragraph a small 8 x 12 hole prototype area
         #end list
                  
         When this board is specified the following defaults are active:
         
         #literal
            #configure chip          lpc2138
            #configure xtal          12 * MHz
            #configure cclk          60 * MHz
            #configure pclk          60 * MHz
            #configure link          arm_usb_ocd

            #configure leds_n        8
            #configure leds_8_pin    55 
            #configure port          com1
            #configure baudrate      %s
         #end literal         
        
         These defaults can be overruled by explicit definitions.
      """  % Mkt_Serial_Baudrate )     
      
      self.Documentation( """         
         #article boards   
         #header olimex_p2148 Olimex P2148 board
         
         #literal
            #configure board olimex_p2148
         #end literal
         
         When the 
         #link mkt_board board 
         is configured as olimex_p2148 MicroKit is configured 
         for the 
         #url http://www.olimex.com Olimex  
         #url http://www.olimex.com/dev/lpc-p2148.html P2148
         board:
      
         #image board-olimex-p2148.jpg
                    
         This board has
         
         #list
            #paragraph an NXP LPC2148 chip 
               with 12 MHz and 32.768 kHz crystals
            #paragraph an USB connector for power;
               the data lines of this connector are connected 
               to the LPC2148 USB pins 
            #paragraph two DB9F serial connectors for downloading 
               and communication, connected to the two UARTs. The one
               connected to UART0 has the hardware for 
               #link lpc-handshake-boot  
               Two mini switches activate this hardware.            
            #paragraph 2 LEDs (connected directly to ARM pins)
            #paragraph a buzzer (small loudspeaker,
               connected directly to two ARM pins)
            #paragraph a trim potentiometer, connected to an ARM A/D pin
            #paragraph a reset button and a button that is connected
               to a reset pin
            #paragraph a connector for a wall-wart (6-9V AC or 8-12V DC)
            #paragraph an ARM-standard 20-pin JTAG connector
            #paragraph a 10-pin Olimex UEXT extension connector
            #paragraph a trim potentiometer, connected to an ARM A/D pin
            #paragraph pin headers for all ARM I/O pins
            #paragraph a 14 x 27 hole prototype area
         #end list
                  
         When this board is specified the following defaults are active:
         
         #literal
            #configure chip          lpc2148
            #configure xtal          12 * MHz
            #configure cclk          60 * MHz
            #configure pclk          60 * MHz
            #configure link          arm_usb_ocd

            #configure leds_n        2
            #configure leds_8_pin    11
            #configure port          com1
            #configure baudrate      %s
         #end literal         
        
         These defaults can be overruled by explicit definitions.
      """  % Mkt_Serial_Baudrate )     
      
      self.Documentation( """         
         #article boards
         #header lpc-handshake-boot LPC reset and bootload using handshake lines
         #index handshake
         
         A serial download to an LPC chip requires that the chip is reset, 
         and the bootload enable pin is held low when the chip leaves reset. 
         By convention these two functions can be controlled by 
         two serial port handshake lines.
         By default it is assumed that your hardware supports this convention.
         If not, 
         //you must disable the use of this feature and 
         you will
         be asked to reset the chip and force it to enter bootload mode by hand
         (probably using switches or jumpers on your board).
         
         //#literal
         //   #configure EA_BOARD     ...
         //   #configure EA_MEMORY    ...
         //   #configure EA_TOOL      ...
         //   #configure EA_HS_BOOT   0
         //#end literal
          
         In order to download code to an LPC ARM chip using the 
         serial bootloader available in these chips the chip must be reset, and
         when it leaves reset it must find pin P0.14 high. 
         Most boards that have a serial connector implement this function.
         For a hands-off download the reset and P0.14 pins can be controlled
         by the serial port handshake lines DTR and RTS. The circuit below
         is the standard circuit for this, as shown in the NXP
         documentation:
         
         #image lpc-handshake-boot-1.gif
         
         The
         //#link 
         flash-magic
         documentation shows a different circuit to achieve the same effect:
         
         #image lpc-handshake-boot-2.gif
         
         Note that this use of the handshake lines can cause trouble when
         a PC application that wants to communicate with your ARM board
         indavertently toggles the DTR line, causing a reset of the board. 
         Most boards offer a way to disable the reset and bootload-enable 
         functions of the handshake lines, often by removing one or two jumpers.
         
         // #link http://water.cse.unsw.edu.au/esdk/lpc2/boot-loader.html
         // #link http://www.myvoice.nl/electronics/      
      """ )
   
class ARM( Target ):
   "ARM chips description"
   "ARM only, no Thumb or Cortex"

   def Code_Directive( self ):
      return ".arm"

   def Long_Jump( self, Target ):
      return "ldr pc, =%s" % Target

   ##########################################################################
   #
   # startup vectors
   #
   ##########################################################################
   
   def Init_Vectors( self ):
      self.UpCall( super( ARM, self ).Init_Vectors )   
              
      self.Documentation( """
         #article exception-vectors ARM exception vectors
         """ )
         
      self.Assembler( """
         //==================================================================
         //
         // ARM exception vectors
         //
         // The "vectors" section is mapped to a 64-byte memory area that is 
         // handled in a special way: when running from ROM its content is 
         // first copied to RAM and next that RAM area is remapped to 
         // address 0. 
         // This makes it possible for a running program to change the 
         // exception (interrupt) vectors
         //
         //==================================================================
         
         // this section is handled in a special way by the link script
         .section vectors, "awx"
         .arm
         .align

         .global _start
         _start:
         
         // the ARM exception vectors, at physical address 0
         ldr     pc, mkt_reset_vector
         ldr     pc, mkt_undefined_instruction_vector
         ldr     pc, mkt_software_interrupt_vector
         ldr     pc, mkt_prefetch_abort_vector
         ldr     pc, mkt_data_abort_vector
         ldr     pc, mkt_reserved_vector
         .global irq_vec
         irq_vec:
         b _mkt_IRQ_interrupt_handler
         // ldr     pc, mkt_IRQ_vector         
         ldr     pc, mkt_FIQ_vector
      
         .global mkt_reset_vector
         .global mkt_undefined_instruction_vector
         .global mkt_software_interrupt_vector
         .global mkt_prefetch_abort_vector
         .global mkt_data_abort_vector
         .global mkt_reserved_vector
         .global mkt_IRQ_vector
         .global mkt_FIQ_vector
      
         //==================================================================
         //
         // The following vectors are variables that contain the addresses 
         // the various execptions will jump to. Change the content of a 
         // vector to redirect the corresponding exception.
         //
         //==================================================================
      
         mkt_reset_vector:                    .word mkt_reset_handler
         mkt_undefined_instruction_vector:    .word mkt_undefined_instruction_handler
         mkt_software_interrupt_vector:       .word mkt_software_interrupt_handler
         mkt_prefetch_abort_vector:           .word mkt_prefetch_abort_handler
         mkt_data_abort_vector:               .word mkt_data_abort_handler
         mkt_reserved_vector:                 .word mkt_reserved_handler
         // mkt_IRQ_vector:                      .word unexp_exc_handler_6
         mkt_IRQ_vector:                      .word _mkt_IRQ_interrupt_handler
         mkt_FIQ_vector:                      .word mkt_FIQ_handler
         
         //==================================================================
         //
         // default unexpected exception handlers
         //
         // These handlers just load a unique value into R0 and jumps 
         // to the mkt_fatal_error handler.
         //
         //==================================================================
      
         mkt_code
         
         mkt_undefined_instruction_handler: 
            .weak mkt_undefined_instruction_handler
            mkt_FATAL mkt_fatal__unhandled_undefined_instruction
            
         mkt_software_interrupt_handler: 
            .weak mkt_software_interrupt_handler
            mkt_FATAL mkt_fatal__unhandled_software_interrupt
            
         mkt_prefetch_abort_handler: 
            .weak mkt_prefetch_abort_handler
            mkt_FATAL mkt_fatal__unhandled_prefetch_abort
            
         mkt_data_abort_handler: 
            .weak mkt_data_abort_handler
            mkt_FATAL mkt_fatal__unhandled_data_abort
            
         mkt_reserved_handler: 
            .weak mkt_reserved_handler
            mkt_FATAL mkt_fatal__unhandled_reserved
            
         unexp_exc_handler_6: mkt_FATAL mkt_fatal__unhandled_IRQ
         
         mkt_FIQ_handler: 
            .weak mkt_FIQ_handler
            mkt_FATAL mkt_fatal__unhandled_FIQ 
         
         mkt_reset_handler:
         
      """ )
      
      # dit veroorzaakt problemen in Udo's zaal...
      if 0: self.C_Header( """
         void ( * mkt_reset_vector )( void );
         void ( * mkt_undefined_instruction_vector )( void );
         void ( * mkt_software_interrupt_vector )( void );
         void ( * mkt_prefetch_abort_vector )( void );
         void ( * mkt_data_abort_vector )( void );
         void ( * mkt_reserved_vector )( void );
         void ( * mkt_IRQ_vector )( void );
         void ( * mkt_FIQ_vector )( void );
      """ )
         
   def Init_Stack( self ):
      self.UpCall( super( ARM, self ).Init_Stack )   
      
      self.Assembler( """
         //==================================================================
         //
         // set stacks
         //
         // note: Early ARM ARM erroneously stated that msr cpsr_c, <imm> 
         // is not an allowed form, and this error can still be found for 
         // instance in Furber's book. 
         // ref: http://www.arm.com/support/faqdev/1472.html
         //
         //==================================================================
         
         mkt_uninitialized
            .global _mkt_first_free
            _mkt_first_free:  .space 4
            
         mkt_code   
      
         // get first free location
         ldr     r6, = _mkt_first_free
         ldr     r5, = mkt_ln_bss_beyond;
         // ldr     r5, [ r6 ]
         str     r5, [ r6 ]
      
         #define MKT_FIQ_STACK_SIZE 2048   
         #define MKT_IRQ_STACK_SIZE 2048   
         #define MKT_MAIN_STACK_SIZE 2048            
         #define ROUND_UP( N, M ) ((N + (M-1)) & ~ (M-1)) 
         
         #ifdef MKT_FIQ_STACK_SIZE

            // select FIQ mode
            msr     cpsr_c, #0x11
            nop

            // claim stack area
            add     r5, r5, #ROUND_UP( MKT_FIQ_STACK_SIZE, 4 )
            
            // set stack pointer
            mov     sp, r5

         #endif

         #ifdef MKT_IRQ_STACK_SIZE

            // select IRQ mode
            msr     cpsr_c, #0x12
            nop

            // claim stack area
            add     r5, r5, #ROUND_UP( MKT_IRQ_STACK_SIZE, 4 )
           
            // set stack pointer
            mov     sp, r5

         #endif

         // select supervisor mode
         msr     cpsr_c, #0x13
         nop

         // select supervisor mode
         //msr     cpsr_c, #0xD3
         //nop
   
         // claim stack area
         add     r5, r5, #ROUND_UP(MKT_MAIN_STACK_SIZE, 4 )

         // set stack pointer
         mov     sp, r5  
         
         // update the 'free ram' pointer
         str     r5, [ r6 ]
      """ )
   
   ##########################################################################
   #
   # ARM fatal error handler
   #
   ##########################################################################

   def Error_Handler( self ):
      self.UpCall( super( ARM, self ).Error_Handler )
      
      self.Assembler_Header( """      
         #if mkt_error_handling != 0 
            .macro mkt_fatal, NN 
               mov     R0, #\\NN
               bl      mkt_fatal_error
            .endm
         #endif
      """ )            

      self.Assembler( """
         //==================================================================
         // fatal error handler
         //==================================================================
      
         #if mkt_error_handling != 0
           
            mkt_data
            
               // overwrite this variable with the address 
               // of your error handler function, but don't assume 
               // too much about the state of the system!
               .global mkt_user_error_vector
               mkt_user_error_vector:  .word mkt_fatal_error
      
            mkt_subroutine mkt_fatal_error
         
               // Insight automatically sets a breakpoint at 'exit'
               // so why not put that label here so a fatal error is caught
               exit: 
         
               // When then debugger stops at this breakpoint a fatal error
               // has occurred during execution. 
               // R0 contains the error code.
               // You can check the stack to see where the error ocurred.
               ldr     r1, =mkt_user_error_vector
               ldr     pc, [ r1 ]           
            
         #endif
      """ )
      
      self.C_Header( """
         #if mkt_error_handling != 0
            extern void (*mkt_user_error_vector)( unsigned int error );
         #endif
      """ )
         
   ##########################################################################
   #
   # ARM busy wait
   #
   ##########################################################################

   def Busy_Wait( self ):
      self.UpCall( super( ARM, self ).Busy_Wait )

      self.Assembler( """
         //===============================================================
         //
         // busy waiting
         //
         // Busy waiting is implemented by a looping. The loop code is 
         // placed in RAM so it will run at full speed, independent from 
         // FLASH (ROM) speed and MAM issues.
         //
         //===============================================================

         mkt_subroutine mkt_busy_wait_us 

         // calculate the number of CPU cycles * 1e6 to wait in r2, r3
         ldr     r1, =mkt_cclk
         umull   r2, r3, r0, r1
         ldr     r0, =(5 * 1000000 ) // the loop is 3 + 2 CPU cycles
   
         // switch to RAM to avoid unpredictable FLASH code fetch delays
         // does not work reliable :(
         mkt_switch_to_ram mkt_RAM_busy_wait_us 
         
         // wovo
         // ldr pc, = joop
         // .section .data.joop // this is OK with -sections, but not without!
         //.data
         //.global joop
         //joop:   
   
         // spend the calculated number of cycles 
         busy_wait_us_loop:
         
         subs    r2, r2, r0
         sbcs    r3, r3, #0
         bcs     busy_wait_us_loop 
   
         // LR contains the full 32-bit return address, 
         // so no special actions needed here.
         mov     pc, lr    
      """ )
   
   ##########################################################################
   #
   # ARM call main
   #
   ##########################################################################

   def Init_Call_Main( self ):
      self.UpCall( super( ARM, self ).Init_Call_Main )

      self.Assembler( """
      
         //==================================================================
         // call pre-initialisation
         //==================================================================
         
         bl      mkt_pre_initialization
         
         //==================================================================
         // call global initializers
         //==================================================================
         
         // b ctors_done
         ldr     r10, =__ctors_start__
         ldr     r11, =__ctors_end__
      ctors_loop:   
         cmp     r10, r11
         beq     ctors_done
         ldr     lr, =ctors_loop
         ldr     pc, [ r10 ], #4
      ctors_done:   

         //==================================================================
         // call main (= the application)
         //==================================================================

         mov     r0, #0   // no arguments
         mov     r1, #0   // no argv either
         bl      main   
         
         .global mkt_return_from_coroutine
      mkt_return_from_coroutine:         
         
         // main should never return
         mkt_fatal mkt_fatal__return_from_main
         
      //   .global mkt_pre_initialization
      //   .weak mkt_pre_initialization
      //mkt_pre_initialization:      
      //   mov     pc, lr
         
      """ )
      
      self.C_Header( """
         #if mkt_error_handling != 0
            void mkt_pre_initialization( void );
         #endif
      """ )
      
      self.C( """
         void mkt_uart0_write_char( char c ){ mkt_uart_char_write (UART0, c); }
         void mkt_pre_initialization( void ){
            mkt_user_error_vector = mkt_default_error_handler;
            mkt_uart_init( UART0, mkt_baudrate );
            mkt_print_vector = mkt_uart0_write_char;      
         }
      """ )
      
      
   ##########################################################################
   #
   # ARM clear BSS segment
   #
   ##########################################################################

   def Init_BSS_Clear( self ):
      self.UpCall( super( ARM, self ).Init_BSS_Clear )

      self.Assembler( """
         //==================================================================
         // clear BSS (non-initialized variables)
         //==================================================================

         mov     r0, #0
         ldr     r1, = mkt_ln_bss_first
         ldr     r2, = mkt_ln_bss_beyond
      clear_bss_loop:
         cmp     r1, r2
         beq     clear_bss_beyond
         str     r0, [ r1 ], #4
         b       clear_bss_loop
      clear_bss_beyond:
      """ )
   
   ##########################################################################
   #
   # ARM copy DATA segment
   #
   ##########################################################################

   def Init_DATA_Copy( self ):
      self.UpCall( super( ARM, self).Init_DATA_Copy )

      Memory = D  = self.Configuration.Get_Value( Mkt_Memory )
      if Memory == Mkt_ROM:
         self.Assembler( """
            //==================================================================
            // copy DATA segment (initialised data, RAM code) from ROM to RAM
            //==================================================================   
               ldr     r1, = mkt_ln_data_rom_first
               ldr     r2, = mkt_ln_data_ram_first
               ldr     r3, = mkt_ln_data_ram_beyond
            copy_data_loop:
               cmp     r3, r2
               beq     copy_data_beyond
               ldr     r0, [ r1 ], #4
               str     r0, [ r2 ], #4
               b       copy_data_loop
            copy_data_beyond:
         """ )     
      
   ##########################################################################
   #
   # ARM init clock
   #
   ##########################################################################
   
   def Init_Clock( self ):
      self.UpCall( super( ARM, self ).Init_Clock )
      
      CCLK = Evaluate( mkt_cclk )
      XTAL = Evaluate( mkt_xtal )
      FEED = """
         // feed the PLL
         ldr     r0, =PLL0FEED
         mov     r1, #0xAA
         str     r1, [ r0 ]
         mov     r1, #0x55
         str     r1, [ r0 ]
      """      
      
      if CCLK == XTAL:
         PLL_Config = """
            // xtal and cclk are the same: disable the PLL
            ldr     r0, =PLL0CON
            ldr     r1, =0
            str     r1, [ r0 ]
            %s
         """ % FEED
      else:
         M = int( CCLK / XTAL )
         if  M * XTAL != CCLK:
            Errors.Raise( "the configure cclk is not a multiple of xtal" )
         if ( M < 1 ) or ( M > 32 ):
            Errors.Raise( "the configured cclk is not an allowd multiple of xtal" )   
         P = int(round( ( 320 * MHz ) / ( 2 * CCLK )))
         CFG = ( P << 5 ) + ( M - 1 )    
         PLL_Config = """
            // set main PLL
            
            // xtal=%d, cclk=%d
            // M=%d, P=%d
            ldr     r0, =PLL0CFG
            ldr     r1, =0x%08X
            str     r1, [ r0 ]
            
            ldr     r0, =PLL0CON
            ldr     r1, =1
            str     r1, [ r0 ]
            %s
            
         pll_init_wait:
            ldr     r0, =PLL0STAT
            ldr     r1, [ r0 ]
            ands    r1, r1, #( 1 << 10)
            beq     pll_init_wait
            
            ldr     r0, =PLL0CON
            ldr     r1, =3
            str     r1, [ r0 ]           
            %s
            
         """ % (
            XTAL, CCLK, M , P, CFG, FEED, FEED )
       

      #define MK_PLL0_P  
      #define MK_PLL0CFG 
   #endif       

      self.Assembler( """
         //==================================================================
         // set clocks and related timing
         //==================================================================

         // first disable MAM
         ldr     r1, =MAMCR
         mov     r0, #0
         str     r0, [ r1 ]

         // Set MAMTIM to appropriate rate  
         ldr     r1, = MAMTIM
         #if mkt_cclk < 20 * MHz
            mov     r0, #1
         #elif mkt_cclk < 40 * MHz
            mov     r0, #2
         #else
            mov     r0, #3
         #endif
         mov     r0, #3
         str     r0, [ r1 ]
   
         // Set MAM fully enabled, as far as possible
         ldr     r1, =MAMCR
         #if mkt_chip == mkt_lpc2148
            // http://www.standardics.nxp.com/
            //    support/documents/microcontrollers/pdf/errata.lpc2148.pdf
            // MAM.2 : Under certain conditions in MAM Mode 2 code execution 
            //            out of internal Flash can fail
            // Note that the advice conflicts with MAM.1 ...
            mov     r0, #1
         #else
            mov     r0, #2
         #endif
         mov     r0, #0
         str     r0, [ r1 ]
      
         // set VPB to the MK_VPBDIV as calculated from the configuration 
         mov     r0, #0
         ldr     r1, = VPBDIV
         str     r0, [ r1 ]

         // alias for chips with only one PLL
         #ifndef PLL0FEED
            #define PLL0FEED PLLFEED
         #endif
      
         %s         
            
      """ % PLL_Config )

   ##########################################################################
   #
   # ARM chip specific inits
   #
   ##########################################################################

   def Init_Chip_Specific( self ):
      self.UpCall( super( ARM, self).Init_Chip_Specific )

      self.Assembler( """
      
         //==================================================================
         //
         // copy the vectors to SRAM
         //
         // when running from RAM is is not needed because the vectors
         // are already at the correct place in RAM 
         //
         //==================================================================
      
         #if 0
         #if mkt_memory == mkt_rom           
               ldr     r1, = mkt_ln_vectors_rom_first
               ldr     r2, = 0x40000000
               ldr     r3, = mkt_ln_vectors_rom_beyond
            copy_vectors_loop:
               ldr     r0, [ r1 ], #4
               str     r0, [ r2 ], #4
               cmp     r3, r1
               bne     copy_vectors_loop         
         #endif
         #endif
         
         //==================================================================
         //
         // remap the first 64 bytes of RAM (the vector block) 
         // to appear (also) at 0x00
         //
         //==================================================================

         #if 0
         #ifdef MEMMAP
            ldr     r0, = MEMMAP
            mov     r1, #10 
            str     r1, [ r0 ]
         #endif
         #endif
         
         //==================================================================
         //
         // select fast or slow GPIO access
         //
         //==================================================================
      
         #ifdef SCS
            #if mkt_fast_gpio == 1
               mov     r0, #3
            #else
               mov     r0, #0
            #endif      
            ldr     r1, =SCS
            str     r0, [ r1 ]      
         #endif
         
      """ )
      
   ##########################################################################
   #
   # ARM chip specific support
   #
   ##########################################################################

   def Chip_Extra( self ):
      self.UpCall( super( ARM, self).Chip_Extra )

      self.Assembler( """
         //==================================================================
         //
         // default IRQ interrupt handler
         //
         // This handler will call the C function that is stored in the
         // VICVectAddr for the interrupt that ocurred. This must be a 
         // *normal* C function, without interrupt attribute.
         //
         //==================================================================

        .text
        .code 32
        .align
 
      
      _mkt_IRQ_interrupt_handler:
         stmfd   sp!, {r0-r12,lr}       // store all regs
         
         ldr     lr, =_mkt_IRQ_interrupt_handler_resume
         ldr     r0, =VICVectAddr       // get handler
         ldr     pc, [ r0 ]             // jump to handler
         
      _mkt_IRQ_interrupt_handler_resume:      
         ldr     r1, =VICVectAddr        
         str     r0, [r1]               // must update priority hardware
      
         ldmfd   sp!, {r0-r12,lr}
         subs    pc, lr, #4             // the way IRQ handler should return  
         
     mkt_subroutine mkt_disable_interrupts
         stmfd           sp!, { r0, lr }
         mrs             r0, CPSR
         orr             r0, r0, #0xC0   // disable IRQ/FIQ interrupts
         msr             CPSR_c, r0
         ldmfd           sp!, { r0, pc }
      
      mkt_subroutine mkt_enable_interrupts
         stmfd           sp!, { r0, lr }
         mrs             r0, CPSR
         bic             r0, r0, #0x80   // enable IRQ interrupts
         msr             CPSR_c, r0
         ldmfd           sp!, { r0, pc }         
        
      """ )        
      
      self.C_Header( """
         void mkt_disable_interrupts( void );
         void mkt_enable_interrupts( void );         
      """ )
      
   ##########################################################################
   #
   # ARM Pin I/O
   #
   ##########################################################################
   
   def Pin_IO( self ):
      self.UpCall( super( ARM, self).Pin_IO )

      self.Documentation( """      
      #article gpio 
         #header gpio-pointers GPIO access using register pointers
      
         The functions described so far in this section provide easy 
         access to the GPIO pins of an ARM chip without the need
         to know the details of the ARM peripheral registers used to
         accomplish this. In some cases this is not sufficient and 
         direct access to these peripheral registers is needed. The
         functions described below can be used to get pointers to
         these registers.
      
         On some ASRM chips there are two sets of registers that
         can be used to control the GPIO pins.
         By default the fastest of these two sets is used, and the
         functions described here return pointers to those
         registers. The configuration parameter
         #link mkt_fast_gpio
         can be used to force the use of the slower set of registers.
      
         The actual peripheral registers that control the GPIO pins are
         the PINSEL (configuration), DIR, SET and CLEAR registers.
         Two bits control the configuration, hence each 16 pins 
         occupy one (32 bit) configuration register. 
      
         These configuration registers are in what the documentation calls 
         the pin connect block. The function MK_GPIO_PINSEL returns a 
         pointer to the configuration register for pin N. 
         A mask for the bits within this register that control pin N can be 
         calculated by shifting the value 3 (two bits with value 1) 
         left ( N % 16 ) times 
         (because each configuration register controls 16 IO pins).
      
         Each set of 32 GPIO pins has four registers that are used to
         set the direction, read the value (for input pins), or 
         to set or clear the value (for output pins).
      
         #anchor PINSEL, MK_GPIO_PINSEL 
         #interface MK_GPIO_PINSEL 
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin selection register
       
         On most ARM chips the configuration of each pin is determined by 2 
         bits per pin.
         These configuration registers are in what the documentation calls 
         the pin connect block. The function MK_GPIO_PINSEL returns a 
         pointer to the configuration register for pin N.
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         
         The two bits for the pin are at bit position ( N % 16 ).
         A mask for the bits within this register that control pin N can be 
         calculated by shifting the value 3 (two bits with value 1) 
         left ( N % 16 ) times 
         (because each configuration register controls 16 IO pins).
      
         In most cases
         the value 00 will configure the pin as GPIO, but better use 
         the pre-defined value 
         #link MK_GPIO_is_GPIO. 
         The effect of the other three configuration values is chip and pin 
         dependent, consult the datasheet for information.
      
         You should probably use this function only when you 
         realy need direct access to a
         PINSEL register of a pin, and that pin is not a constant. The function
         #link mkt_pin_configure 
         function provides an easier way to
         configure a pin as GPIO and set its direction. If it you need
         the PINSEL register and the pin number
         is a constant you could save code by using one of the DIR
         registers directly.
      """ )
      
      self.C_Header( """
         //==================================================================
         //
         // GPIO pins : get register addresses: PINSEL, DIR, PIN, SET, CLR 
         //
         //==================================================================
      
            volatile /* "C" */ unsigned int* mkt_gpio_pinsel( int N );
         
         // tbw
         #ifndef IO0DIR
            #define IO0DIR IODIR 
         #endif
         #ifndef IO0PIN
            #define IO0PIN IOPIN
         #endif
         #ifndef FIO0PIN
            #define FIO0PIN FIOPIN
         #endif
         
         #ifndef IO0SET
            #define IO0SET IOSET
         #endif
         #ifndef FIO0SET
            #define FIO0SET FIOSET
         #endif
         #ifndef IO0CLR
            #define IO0CLR IOCLR
         #endif
         #ifndef FIO0CLR
            #define FIO0CLR FIOCLR
         #endif
      """ )
      
      self.C( """
         volatile unsigned int* mkt_gpio_pinsel( int N ){ 
            #ifdef PINSEL0
               if( N < 16 ) return & PINSEL0;
            #endif
            #ifdef PINSEL1
               if( N < 32 ) return & PINSEL1;
            #endif
            #ifdef PINSEL2
               if( N < 48 ) return & PINSEL1;
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      """ )
 
      self.Documentation( """
      
      #article gpio
      
         #anchor DIR, MK_GPIO_DIR
         #interface MK_GPIO_DIR
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin direction register
       
         The function MK_GPIO_DIR returns a pointer to the direction register
         for pin N.
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         In most ARM chips each pin has 1 bit in a DIR register.
         This bit controls, for pins that are specified as GPIO in the 
         #link PINSEL 
         register, whether the pin is an input or an output pin.
         In most ARM chip a 0 specifies the pin as input, a 1 specifies
         the pin as output, and the default (reset) state is input.
         (But an application should never rely on this reset state.)
      
         A mask for the bit within this register that controls pin N can be 
         calculated by shifting the value 1 left ( N % 32 ) times 
         (because each direction register controls 32 IO pins).
      
         Use this function only when you realy need direct access to a
         DIR register of a pin, and that pin is not a constant. The
         #link mkt_pin_configure 
         function provides an easier way to
         configure a pin as GPIO and set its direction. If it you need
         the DIR register and the pin number
         is a constant you could save code by using one of the DIR
         registers directly.
      """ )
      
      self.C_Header( """
         volatile /* "C" */ unsigned int* mkt_gpio_dir( int N );
      """ )
         
      self.C( """
      
         volatile unsigned int* mkt_gpio_dir( int N ){
            #if mkt_fast_gpio == 1
               #ifdef FIO0DIR
                  if( N < 32 ) return & FIO0DIR;
               #endif
               #ifdef FIO1DIR
                  if( N < 64 ) return & FIO1DIR;
               #endif
            #else
               #ifdef IO0DIR
                  if( N < 32 ) return & IO0DIR;
               #endif
               #ifdef IO1DIR
                  if( N < 64 ) return & IO1DIR;
                #endif
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      """ )
      
      self.Documentation( """      
      #article gpio
      
         #anchor PIN
         #interface MK_GPIO_PIN
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin value register
         
         The function MK_GPIO_PIN returns a pointer to the PIN (value) register
         for pin N. These registers 
         can be used to read the current level of pins that 
         are configured for input.
         For this to work the pin must be configured as GPIO (check 
         #link MK_GPIO_PINSEL) 
         and configured as input (check 
         #link MK_GPIO_DIR). 
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
      
         A mask for the bit within this register that contains the value for
         pin N can be calculated by shifting the value 1 left ( N % 32 ) times 
         (because each PIN register accesses 32 IO pins).
      
         Use this function only when you realy need direct access to a
         PIN register of a pin, and that pin is not a constant. The
         #link mkt_pin_read function provides an easier way to
         read the valueof a GPIO pin. If it you need
         a PIN register and the pin number
         is a constant you could save code by using one of the PIN
         registers directly.
      """ )
      
      self.C_Header( """
         volatile /* "C" */ unsigned int* mkt_gpio_pin( int N );
      """ )
         
      self.C( """
      
         volatile unsigned int* mkt_gpio_pin( int N ){
            #if mkt_fast_gpio == 1
               #ifdef FIO0PIN
                  if( N < 32 ) return & FIO0PIN;
               #endif
               #ifdef FIO1PIN
                  if( N < 64 ) return & FIO1PIN;
               #endif
            #else
               #ifdef IO0PIN
                  if( N < 32 ) return & IO0PIN;
               #endif
               #ifdef IO1PIN
                  if( N < 64 ) return & IO1PIN;
               #endif
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      """ )
      
      self.Documentation( """
      
      #article gpio
      
         #anchor SET, CLEAR
         #interface MK_GPIO_SET
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin set register
      
         #interface MK_GPIO_CLEAR
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin clear register
      
         The functions MK_GPIO_SET and MK_GPIO_CLEAR return pointers to
         the SET and CLEAR registers for pin N.
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         These registers are used to set the value GPIO pins that 
         are configured as output pins.
         Writing a value to one of these registers affects only the 
         pins for which the corresponding bit is a 1: when writing to
         the SET register such pins are set (made high), when writing to
         the CLEAR register such pins are cleared (made low).
         Note that is makes it unnecessary to read these registers.
      
         For this to work the pin must be configured as GPIO (check 
         #link MK_GPIO_PINSEL) 
         and configured as output (check 
         #link MK_GPIO_DIR).
      
         Note that in order to clear a pin (make it low) you
         must write a value to the CLR register that has a 1 in
         the corresponding bit position. 
      
         Use these functions only when you realy need direct access to a
         SET register of a pin, and that pin is not a constant.
         The 
         #link mkt_pin_write 
         function provides an easier way to
         set the value of a GPIO pin. If it you need
         a SET or CLEAR register and the pin number
         is a constant you could save code by using the
         register directly.
         
         // int MK_GPIO_Mask( int N ); ?
         
         // example?
         
      """ )   
         
      self.C_Header( """
            volatile /* "C" */ unsigned int* mkt_gpio_set( int N );
            volatile /* "C" */ unsigned int* mkt_gpio_clr( int N );
      """ )
            
      self.C( """
      
         volatile unsigned int* mkt_gpio_set( int N ){
            #if mkt_fast_gpio == 1
               #ifdef FIO0SET
                  if( N < 32 ) return & FIO0SET;
               #endif
               #ifdef FIO1SET
                  if( N < 64 ) return & FIO1SET;
               #endif
            #else
               #ifdef IO0SET
                  if( N < 32 ) return & IO0SET;
               #endif
               #ifdef IO1SET
                  if( N < 64 ) return & IO1SET;
               #endif
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      
         volatile unsigned int* mkt_gpio_clr( int N ){
            #if mkt_fast_gpio == 1
               #ifdef FIO0CLR
                  if( N < 32 ) return & FIO0CLR;
               #endif
               #ifdef FIO1CLR
                  if( N < 64 ) return & FIO1CLR;
               #endif
            #else
               #ifdef IO0CLR
                  if( N < 32 ) return & IO0CLR;
               #endif
               #ifdef IO1CLR
                  if( N < 64 ) return & IO1CLR;
               #endif
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      """ ) 

      self.C( """      
         void /* "C" */ mkt_pin_direction( int N, int D ){
         
            // make it an input or output
            if( D == mkt_output ){
               *mkt_gpio_dir( N ) |= 1 << ( N % 32 );
            } else {
               *mkt_gpio_dir( N ) &= ~( 1 << ( N % 32 ));
            }
         }
         
         void /* "C" */ mkt_pin_configure( int N, int D ){
         
            // make the pin a GPIO pin
            mkt_pin_connect( N, 0 );
            
            // make it an input or output
            mkt_pin_direction( N, D );
         }
      
         void mkt_pin_write( int N, int V ){
            if( V ){
               *mkt_gpio_set( N ) = 1 << ( N % 32 );
            } else {
               *mkt_gpio_clr( N ) = 1 << ( N % 32 );
            }
         }
         
         unsigned char mkt_pin_read( int N ){ 
            return ((* mkt_gpio_pin( N )) & ( 1 << ( N % 32 ))) != 0;
         }
     
         void mkt_pin_connect( int N, int C ){
            volatile unsigned int *p;
            if( N < 32 + 16 ){
               p = mkt_gpio_pinsel( N );
               *p &=~ ( 3 << ( 2 * ( N % 16 )));
               *p |= ( C & 0x03 ) << ( 2 * ( N % 16 ));
            } else if( N < 32 + 26 ) {
               PINSEL2 &= ~0x04;
            } else {
               PINSEL2 &= ~0x08;
            }
         }

         void mkt_pin_set( int pin ){
            *mkt_gpio_set( pin ) = 1 << ( pin % 32 );
         }
         void mkt_pin_clear( int pin ){
            *mkt_gpio_clr( pin ) = 1 << ( pin % 32 );
         }
            
         
      """ )
                   
      self.C_Header( """
         // to simplify coding, it is sort-of assumed that 4 x 32 = 96 I/O's
         // are be present. The missing pointers are decleard as __mkt_dummy
         // to simplify the coding further, the MKT_IO... macro's are used,
         // which point to the legacy or the fast IO's, as configured
         extern unsigned volatile int __mkt_dummy;
         
         // this variable will be linked in to indicate that an invalid
         // pin number is used in a fixed-pin basic I/O macro call
         extern volatile unsigned int _MKT_INVALID_PIN_NUMBER;
         
         """ 
         + "\n" )  
         
      self.Assembler_And_C_Header(
         self.IO_Unification( "         " ).replace( "%NUMBER_OF_PINS", "64" ) )
         
      self.C( """
         unsigned volatile int __mkt_dummy;
      """ )   
         
      self.C_Header( """
               
         #define mkt_fixed_pin_input( pin ){ \\
            *MKT_GPIO_DIR( pin ) &= ~( 1 << ( pin % 32 )); }
         
         #define mkt_fixed_pin_output( pin ){ \\
            *MKT_GPIO_DIR( pin ) |= 1 << ( pin % 32 ); }
         
         #define mkt_fixed_pin_direction( pin, direction ) \\
            if( direction == mkt_output ){ \\
               mkt_fixed_pin_output( pin ); \\
            } else { \\
               mkt_fixed_pin_input( pin ); \\
            }
            
         #define mkt_fixed_pin_configure( pin, direction ){ \\
            *MKT_GPIO_SEL( pin ) &= ~( 3 << MKT_GPIO_SEL_OFFSET( pin )); \\
            mkt_fixed_pin_direction( pin, direction ); }
         
         #define mkt_fixed_pin_read( pin ) ( \\
            *MKT_GPIO_PIN( pin ) & ( 1 << ( pin % 32 )))
         
         #define mkt_fixed_pin_set( pin ){ \\
            *MKT_GPIO_SET( pin ) = ( 1 << ( pin % 32 )); }
         
         #define mkt_fixed_pin_clear( pin ){ \\
            *MKT_GPIO_CLR( pin ) = ( 1 << ( pin % 32 )); }
           
         #define mkt_fixed_pin_write( pin, value ) \\
            if( value ){ \\
               mkt_fixed_pin_set( pin ); \\
            } else { \\
               mkt_fixed_pin_clear( pin ); \\
            }         
      """ )
      
   def IO_Unification_Base( self, Text, Fast ):
      for Reg in [ "DIR", "SET", "CLR", "PIN", "SEL" ]:
         for Nr in [ "0", "1", "2", "3" ]:
            Name = "IO%s%s" % ( Nr, Reg )
            Fast_Name = "%s%s" % ( Fast, Name )
            Text.Add( "   #ifdef %s" % Fast_Name )
            Text.Add( "      #define MKT_%s %s" % ( Name, Fast_Name ))
            Text.Add( "   #else" )
            Text.Add( "      #define MKT_%s __mkt_dummy" % Name )
            Text.Add( "   #endif" )
            
   def IO_Unification_Pointer( self, Text ):
      for Name in [ "DIR", "SET", "CLR", "PIN" ]:
         Text.Add( "#define MKT_GPIO_%s( pin )( \\" % Name )
         Text.Add( "   ( pin >= %NUMBER_OF_PINS ) ? &_MKT_INVALID_PIN_NUMBER \\" )
         for Nr in [ 0, 1, 2, 3 ]:     
            Text.Add( "   : ( pin < ( %d + 32 )) ? &MKT_IO%d%s \\" 
               % ( Nr * 32, Nr, Name ))
         Text.Add( "   : &__mkt_dummy )" )
         
      Text.Add( "#define MKT_GPIO_SEL( pin )( \\" )
      Text.Add( "   ( pin >= %NUMBER_OF_PINS ) ? &_MKT_INVALID_PIN_NUMBER \\" )
      Text.Add( "   : ( pin >= 31 ) ? &MKT_IO2SEL \\" )
      for Nr in [ 0, 1, 2, 3 ]:
         Text.Add( "    : ( pin < ( %d + 16 )) ? &MKT_IO%dSEL \\" 
            % ( Nr * 16, Nr ))
      Text.Add( "    : &__mkt_dummy )" )
      
      Text.Add( "#define MKT_GPIO_SEL_OFFSET( pin )( \\" )
      Text.Add( "   ( pin < 32 ) ? (( pin % 16 ) * 2 ) \\" )
      Text.Add( "   : ( pin < 32 + 26 ) ? 3 \\" )
      Text.Add( "   : ( pin < 32 + 37 ) ? 2 \\" )
      Text.Add( "   : __mkt_dummy )" )
         
   def IO_Unification( self, Prefix ):      
      Text = Lines()
      Text.Add( "#if mkt_fast_gpio == 1" )
      self.IO_Unification_Base( Text, "F" )
      Text.Add( "#else" )
      self.IO_Unification_Base( Text, "" )
      Text.Add( "#endif" )
      self.IO_Unification_Pointer( Text )
      return Text.Plain_Text( Prefix )
      
class PIC32( Target ):
   "PIC32 chips description"

   def Code_Directive( self ):
      return ".arm"

   def Long_Jump( self, Target ):
      return "ldr pc, =%s" % Target

   ##########################################################################
   #
   # startup vectors
   #
   ##########################################################################
   
   def Init_Vectors( self ):
      self.UpCall( super( PIC32, self ).Init_Vectors )   
              
      self.Documentation( """
         #article exception-vectors ARM exception vectors
         """ )
         
      self.Assembler( """
         //==================================================================
         //
         // ARM exception vectors
         //
         // The "vectors" section is mapped to a 64-byte memory area that is 
         // handled in a special way: when running from ROM its content is 
         // first copied to RAM and next that RAM area is remapped to 
         // address 0. 
         // This makes it possible for a running program to change the 
         // exception (interrupt) vectors
         //
         //==================================================================
         
         // this section is handled in a special way by the link script
         .section vectors, "awx"
         .arm
         .align

         .global _start
         _start:
         
         // the ARM exception vectors, at physical address 0
         ldr     pc, mkt_reset_vector
         ldr     pc, mkt_undefined_instruction_vector
         ldr     pc, mkt_software_interrupt_vector
         ldr     pc, mkt_prefetch_abort_vector
         ldr     pc, mkt_data_abort_vector
         ldr     pc, mkt_reserved_vector
         .global irq_vec
         irq_vec:
         b _mkt_IRQ_interrupt_handler
         // ldr     pc, mkt_IRQ_vector         
         ldr     pc, mkt_FIQ_vector
      
         .global mkt_reset_vector
         .global mkt_undefined_instruction_vector
         .global mkt_software_interrupt_vector
         .global mkt_prefetch_abort_vector
         .global mkt_data_abort_vector
         .global mkt_reserved_vector
         .global mkt_IRQ_vector
         .global mkt_FIQ_vector
      
         //==================================================================
         //
         // The following vectors are variables that contain the addresses 
         // the various execptions will jump to. Change the content of a 
         // vector to redirect the corresponding exception.
         //
         //==================================================================
      
         mkt_reset_vector:                    .word mkt_reset_handler
         mkt_undefined_instruction_vector:    .word mkt_undefined_instruction_handler
         mkt_software_interrupt_vector:       .word mkt_software_interrupt_handler
         mkt_prefetch_abort_vector:           .word mkt_prefetch_abort_handler
         mkt_data_abort_vector:               .word mkt_data_abort_handler
         mkt_reserved_vector:                 .word mkt_reserved_handler
         // mkt_IRQ_vector:                      .word unexp_exc_handler_6
         mkt_IRQ_vector:                      .word _mkt_IRQ_interrupt_handler
         mkt_FIQ_vector:                      .word mkt_FIQ_handler
         
         //==================================================================
         //
         // default unexpected exception handlers
         //
         // These handlers just load a unique value into R0 and jumps 
         // to the mkt_fatal_error handler.
         //
         //==================================================================
      
         mkt_code
         
         mkt_undefined_instruction_handler: 
            .weak mkt_undefined_instruction_handler
            mkt_FATAL mkt_fatal__unhandled_undefined_instruction
            
         mkt_software_interrupt_handler: 
            .weak mkt_software_interrupt_handler
            mkt_FATAL mkt_fatal__unhandled_software_interrupt
            
         mkt_prefetch_abort_handler: 
            .weak mkt_prefetch_abort_handler
            mkt_FATAL mkt_fatal__unhandled_prefetch_abort
            
         mkt_data_abort_handler: 
            .weak mkt_data_abort_handler
            mkt_FATAL mkt_fatal__unhandled_data_abort
            
         mkt_reserved_handler: 
            .weak mkt_reserved_handler
            mkt_FATAL mkt_fatal__unhandled_reserved
            
         unexp_exc_handler_6: mkt_FATAL mkt_fatal__unhandled_IRQ
         
         mkt_FIQ_handler: 
            .weak mkt_FIQ_handler
            mkt_FATAL mkt_fatal__unhandled_FIQ 
         
         mkt_reset_handler:
         
      """ )
      
      # dit veroorzaakt problemen in Udo's zaal...
      if 0: self.C_Header( """
         void ( * mkt_reset_vector )( void );
         void ( * mkt_undefined_instruction_vector )( void );
         void ( * mkt_software_interrupt_vector )( void );
         void ( * mkt_prefetch_abort_vector )( void );
         void ( * mkt_data_abort_vector )( void );
         void ( * mkt_reserved_vector )( void );
         void ( * mkt_IRQ_vector )( void );
         void ( * mkt_FIQ_vector )( void );
      """ )
         
   def Init_Stack( self ):
      self.UpCall( super( PIC32, self ).Init_Stack )   
      
      self.Assembler( """
         //==================================================================
         //
         // set stacks
         //
         // note: Early ARM ARM erroneously stated that msr cpsr_c, <imm> 
         // is not an allowed form, and this error can still be found for 
         // instance in Furber's book. 
         // ref: http://www.arm.com/support/faqdev/1472.html
         //
         //==================================================================
      
         // get first free location
         ldr     r6, = _mkt_first_free
         ldr     r5, = mkt_ln_bss_beyond; // [ r6 ]
         // ldr     r5, [ r6 ]
      
         #define MKT_FIQ_STACK_SIZE 2048   
         #define MKT_IRQ_STACK_SIZE 2048   
         #define MKT_MAIN_STACK_SIZE 2048            
         #define ROUND_UP( N, M ) ((N + (M-1)) & ~ (M-1)) 
         
         #ifdef MKT_FIQ_STACK_SIZE

            // select FIQ mode
            msr     cpsr_c, #0x11
            nop

            // claim stack area
            add     r5, r5, #ROUND_UP( MKT_FIQ_STACK_SIZE, 4 )
            
            // set stack pointer
            mov     sp, r5

         #endif

         #ifdef MKT_IRQ_STACK_SIZE

            // select IRQ mode
            msr     cpsr_c, #0x12
            nop

            // claim stack area
            add     r5, r5, #ROUND_UP( MKT_IRQ_STACK_SIZE, 4 )
           
            // set stack pointer
            mov     sp, r5

         #endif

         // select supervisor mode
         msr     cpsr_c, #0x13
         nop

         // select supervisor mode
         //msr     cpsr_c, #0xD3
         //nop
   
         // claim stack area
         add     r5, r5, #ROUND_UP(MKT_MAIN_STACK_SIZE, 4 )

         // set stack pointer
         mov     sp, r5  
         
         // update the 'first free ram' pointer
         str     r5, [ r6 ]
      """ )
   
   ##########################################################################
   #
   # ARM fatal error handler
   #
   ##########################################################################

   def Error_Handler( self ):
      self.UpCall( super( PIC32, self ).Error_Handler )
      
      self.Assembler_Header( """      
         #if mkt_error_handling != 0 
            .macro mkt_fatal, NN 
               mov     R0, #\\NN
               bl      mkt_fatal_error
            .endm
         #endif
      """ )            

      self.Assembler( """
         //==================================================================
         // fatal error handler
         //==================================================================
      
         #if mkt_error_handling != 0
           
            mkt_data
            
               // overwrite this variable with the address 
               // of your error handler function, but don't assume 
               // too much about the state of the system!
               .global mkt_user_error_vector
               mkt_user_error_vector:  .word mkt_fatal_error
      
            mkt_subroutine mkt_fatal_error
         
               // Insight automatically sets a breakpoint at 'exit'
               // so why not put that label here so a fatal error is caught
               exit: 
         
               // When then debugger stops at this breakpoint a fatal error
               // has occurred during execution. 
               // R0 contains the error code.
               // You can check the stack to see where the error ocurred.
               ldr     r1, =mkt_user_error_vector
               ldr     pc, [ r1 ]           
            
         #endif
      """ )
      
      self.C_Header( """
         #if mkt_error_handling != 0
            extern void (*mkt_user_error_vector)( unsigned int error );
         #endif
      """ )
         
   ##########################################################################
   #
   # ARM busy wait
   #
   ##########################################################################

   def Busy_Wait( self ):
      self.UpCall( super( PIC32, self ).Busy_Wait )

      self.Assembler( """
         //===============================================================
         //
         // busy waiting
         //
         // Busy waiting is implemented by a looping. The loop code is 
         // placed in RAM so it will run at full speed, independent from 
         // FLASH (ROM) speed and MAM issues.
         //
         //===============================================================

         mkt_subroutine mkt_busy_wait_us 

         // calculate the number of CPU cycles * 1e6 to wait in r2, r3
         ldr     r1, =mkt_cclk
         umull   r2, r3, r0, r1
         ldr     r0, =(5 * 1000000 ) // the loop is 3 + 2 CPU cycles
   
         // switch to RAM to avoid unpredictable FLASH code fetch delays
         // does not work reliable :(
         mkt_switch_to_ram mkt_RAM_busy_wait_us 
         
         // wovo
         // ldr pc, = joop
         // .section .data.joop // this is OK with -sections, but not without!
         //.data
         //.global joop
         //joop:   
   
         // spend the calculated number of cycles 
         busy_wait_us_loop:
         
         subs    r2, r2, r0
         sbcs    r3, r3, #0
         bcs     busy_wait_us_loop 
   
         // LR contains the full 32-bit return address, 
         // so no special actions needed here.
         mov     pc, lr    
      """ )
   
   ##########################################################################
   #
   # ARM call main
   #
   ##########################################################################

   def Init_Call_Main( self ):
      self.UpCall( super( PIC32, self ).Init_Call_Main )

      self.Assembler( """
      
         //==================================================================
         // call global initializers
         //==================================================================
         
         // b ctors_done
         ldr     r10, =__ctors_start__
         ldr     r11, =__ctors_end__
      ctors_loop:   
         cmp     r10, r11
         beq     ctors_done
         ldr     lr, =ctors_loop
         ldr     pc, [ r10 ], #4
      ctors_done:   

         //==================================================================
         // call main (= the application)
         //==================================================================

         mov     r0, #0   // no arguments
         mov     r1, #0   // no argv either
         bl      main   
         
         .global mkt_return_from_coroutine
      mkt_return_from_coroutine:         
         
         // main should never return
         mkt_fatal mkt_fatal__return_from_main
         
      """ )
      
   ##########################################################################
   #
   # ARM clear BSS segment
   #
   ##########################################################################

   def Init_BSS_Clear( self ):
      self.UpCall( super( PIC32, self ).Init_BSS_Clear )

      self.Assembler( """
         //==================================================================
         // clear BSS (non-initialized variables)
         //==================================================================

         mov     r0, #0
         ldr     r1, = mkt_ln_bss_first
         ldr     r2, = mkt_ln_bss_beyond
      clear_bss_loop:
         cmp     r1, r2
         beq     clear_bss_beyond
         str     r0, [ r1 ], #4
         b       clear_bss_loop
      clear_bss_beyond:
      """ )
   
   ##########################################################################
   #
   # ARM copy DATA segment
   #
   ##########################################################################

   def Init_DATA_Copy( self ):
      self.UpCall( super( PIC32, self).Init_DATA_Copy )

      Memory = D  = self.Configuration.Get_Value( Mkt_Memory )
      if Memory == Mkt_ROM:
         self.Assembler( """
            //==================================================================
            // copy DATA segment (initialised data, RAM code) from ROM to RAM
            //==================================================================   
               ldr     r1, = mkt_ln_data_rom_first
               ldr     r2, = mkt_ln_data_ram_first
               ldr     r3, = mkt_ln_data_ram_beyond
            copy_data_loop:
               cmp     r3, r2
               beq     copy_data_beyond
               ldr     r0, [ r1 ], #4
               str     r0, [ r2 ], #4
               b       copy_data_loop
            copy_data_beyond:
         """ )     
      
   ##########################################################################
   #
   # ARM init clock
   #
   ##########################################################################
   
   def Init_Clock( self ):
      self.UpCall( super( PIC32, self ).Init_Clock )
      
      CCLK = Evaluate( mkt_cclk )
      XTAL = Evaluate( mkt_xtal )
      FEED = """
         // feed the PLL
         ldr     r0, =PLL0FEED
         mov     r1, #0xAA
         str     r1, [ r0 ]
         mov     r1, #0x55
         str     r1, [ r0 ]
      """      
      
      if CCLK == XTAL:
         PLL_Config = """
            // xtal and cclk are the same: disable the PLL
            ldr     r0, =PLL0CON
            ldr     r1, =0
            str     r1, [ r0 ]
            %s
         """ % FEED
      else:
         M = int( CCLK / XTAL )
         if  M * XTAL != CCLK:
            Errors.Raise( "the configure cclk is not a multiple of xtal" )
         if ( M < 1 ) or ( M > 32 ):
            Errors.Raise( "the configured cclk is not an allowd multiple of xtal" )   
         P = int(round( ( 320 * MHz ) / ( 2 * CCLK )))
         CFG = ( P << 5 ) + ( M - 1 )    
         PLL_Config = """
            // set main PLL
            
            // xtal=%d, cclk=%d
            // M=%d, P=%d
            ldr     r0, =PLL0CFG
            ldr     r1, =0x%08X
            str     r1, [ r0 ]
            
            ldr     r0, =PLL0CON
            ldr     r1, =1
            str     r1, [ r0 ]
            %s
            
         pll_init_wait:
            ldr     r0, =PLL0STAT
            ldr     r1, [ r0 ]
            ands    r1, r1, #( 1 << 10)
            beq     pll_init_wait
            
            ldr     r0, =PLL0CON
            ldr     r1, =3
            str     r1, [ r0 ]           
            %s
            
         """ % (
            XTAL, CCLK, M , P, CFG, FEED, FEED )
       

      #define MK_PLL0_P  
      #define MK_PLL0CFG 
   #endif       

      self.Assembler( """
         //==================================================================
         // set clocks and related timing
         //==================================================================

         // first disable MAM
         ldr     r1, =MAMCR
         mov     r0, #0
         str     r0, [ r1 ]

         // Set MAMTIM to appropriate rate  
         ldr     r1, = MAMTIM
         #if mkt_cclk < 20 * MHz
            mov     r0, #1
         #elif mkt_cclk < 40 * MHz
            mov     r0, #2
         #else
            mov     r0, #3
         #endif
         mov     r0, #3
         str     r0, [ r1 ]
   
         // Set MAM fully enabled, as far as possible
         ldr     r1, =MAMCR
         #if mkt_chip == mkt_lpc2148
            // http://www.standardics.nxp.com/
            //    support/documents/microcontrollers/pdf/errata.lpc2148.pdf
            // MAM.2 : Under certain conditions in MAM Mode 2 code execution 
            //            out of internal Flash can fail
            // Note that the advice conflicts with MAM.1 ...
            mov     r0, #1
         #else
            mov     r0, #2
         #endif
         mov     r0, #0
         str     r0, [ r1 ]
      
         // set VPB to the MK_VPBDIV as calculated from the configuration 
         mov     r0, #0
         ldr     r1, = VPBDIV
         str     r0, [ r1 ]

         // alias for chips with only one PLL
         #ifndef PLL0FEED
            #define PLL0FEED PLLFEED
         #endif
      
         %s         
            
      """ % PLL_Config )

   ##########################################################################
   #
   # ARM chip specific inits
   #
   ##########################################################################

   def Init_Chip_Specific( self ):
      self.UpCall( super( PIC32, self).Init_Chip_Specific )

      self.Assembler( """
      
         //==================================================================
         //
         // copy the vectors to SRAM
         //
         // when running from RAM is is not needed because the vectors
         // are already at the correct place in RAM 
         //
         //==================================================================
      
         #if 0
         #if mkt_memory == mkt_rom           
               ldr     r1, = mkt_ln_vectors_rom_first
               ldr     r2, = 0x40000000
               ldr     r3, = mkt_ln_vectors_rom_beyond
            copy_vectors_loop:
               ldr     r0, [ r1 ], #4
               str     r0, [ r2 ], #4
               cmp     r3, r1
               bne     copy_vectors_loop         
         #endif
         #endif
         
         //==================================================================
         //
         // remap the first 64 bytes of RAM (the vector block) 
         // to appear (also) at 0x00
         //
         //==================================================================

         #if 0
         #ifdef MEMMAP
            ldr     r0, = MEMMAP
            mov     r1, #10 
            str     r1, [ r0 ]
         #endif
         #endif
         
         //==================================================================
         //
         // select fast or slow GPIO access
         //
         //==================================================================
      
         #ifdef SCS
            #if mkt_fast_gpio == 1
               mov     r0, #3
            #else
               mov     r0, #0
            #endif      
            ldr     r1, =SCS
            str     r0, [ r1 ]      
         #endif
         
      """ )
      
   ##########################################################################
   #
   # ARM chip specific support
   #
   ##########################################################################

   def Chip_Extra( self ):
      self.UpCall( super( PIC32, self).Chip_Extra )

      self.Assembler( """
         //==================================================================
         //
         // default IRQ interrupt handler
         //
         // This handler will call the C function that is stored in the
         // VICVectAddr for the interrupt that ocurred. This must be a 
         // *normal* C function, without interrupt attribute.
         //
         //==================================================================

        .text
        .code 32
        .align
 
      
      _mkt_IRQ_interrupt_handler:
         stmfd   sp!, {r0-r12,lr}       // store all regs
         
         ldr     lr, =_mkt_IRQ_interrupt_handler_resume
         ldr     r0, =VICVectAddr       // get handler
         ldr     pc, [ r0 ]             // jump to handler
         
      _mkt_IRQ_interrupt_handler_resume:      
         ldr     r1, =VICVectAddr        
         str     r0, [r1]               // must update priority hardware
      
         ldmfd   sp!, {r0-r12,lr}
         subs    pc, lr, #4             // the way IRQ handler should return  
         
     mkt_subroutine mkt_disable_interrupts
         stmfd           sp!, { r0, lr }
         mrs             r0, CPSR
         orr             r0, r0, #0xC0   // disable IRQ/FIQ interrupts
         msr             CPSR_c, r0
         ldmfd           sp!, { r0, pc }
      
      mkt_subroutine mkt_enable_interrupts
         stmfd           sp!, { r0, lr }
         mrs             r0, CPSR
         bic             r0, r0, #0x80   // enable IRQ interrupts
         msr             CPSR_c, r0
         ldmfd           sp!, { r0, pc }         
        
      """ )        
      
      self.C_Header( """
         void mkt_disable_interrupts( void );
         void mkt_enable_interrupts( void );         
      """ )
      
   ##########################################################################
   #
   # ARM Pin I/O
   #
   ##########################################################################
   
   def Pin_IO( self ):
      self.UpCall( super( PIC32, self).Pin_IO )

      self.Documentation( """      
      #article gpio 
         #header gpio-pointers GPIO access using register pointers
      
         The functions described so far in this section provide easy 
         access to the GPIO pins of an ARM chip without the need
         to know the details of the ARM peripheral registers used to
         accomplish this. In some cases this is not sufficient and 
         direct access to these peripheral registers is needed. The
         functions described below can be used to get pointers to
         these registers.
      
         On some ASRM chips there are two sets of registers that
         can be used to control the GPIO pins.
         By default the fastest of these two sets is used, and the
         functions described here return pointers to those
         registers. The configuration parameter
         #link mkt_fast_gpio
         can be used to force the use of the slower set of registers.
      
         The actual peripheral registers that control the GPIO pins are
         the PINSEL (configuration), DIR, SET and CLEAR registers.
         Two bits control the configuration, hence each 16 pins 
         occupy one (32 bit) configuration register. 
      
         These configuration registers are in what the documentation calls 
         the pin connect block. The function MK_GPIO_PINSEL returns a 
         pointer to the configuration register for pin N. 
         A mask for the bits within this register that control pin N can be 
         calculated by shifting the value 3 (two bits with value 1) 
         left ( N % 16 ) times 
         (because each configuration register controls 16 IO pins).
      
         Each set of 32 GPIO pins has four registers that are used to
         set the direction, read the value (for input pins), or 
         to set or clear the value (for output pins).
      
         #anchor PINSEL, MK_GPIO_PINSEL 
         #interface MK_GPIO_PINSEL 
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin selection register
       
         On most ARM chips the configuration of each pin is determined by 2 
         bits per pin.
         These configuration registers are in what the documentation calls 
         the pin connect block. The function MK_GPIO_PINSEL returns a 
         pointer to the configuration register for pin N.
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         
         The two bits for the pin are at bit position ( N % 16 ).
         A mask for the bits within this register that control pin N can be 
         calculated by shifting the value 3 (two bits with value 1) 
         left ( N % 16 ) times 
         (because each configuration register controls 16 IO pins).
      
         In most cases
         the value 00 will configure the pin as GPIO, but better use 
         the pre-defined value 
         #link MK_GPIO_is_GPIO. 
         The effect of the other three configuration values is chip and pin 
         dependent, consult the datasheet for information.
      
         You should probably use this function only when you 
         realy need direct access to a
         PINSEL register of a pin, and that pin is not a constant. The function
         #link mkt_pin_configure 
         function provides an easier way to
         configure a pin as GPIO and set its direction. If it you need
         the PINSEL register and the pin number
         is a constant you could save code by using one of the DIR
         registers directly.
      """ )
      
      self.C_Header( """
         //==================================================================
         //
         // GPIO pins : get register addresses: PINSEL, DIR, PIN, SET, CLR 
         //
         //==================================================================
      
            volatile /* "C" */ unsigned int* mkt_gpio_pinsel( int N );
         
         // tbw
         #ifndef IO0DIR
            #define IO0DIR IODIR 
         #endif
         #ifndef IO0PIN
            #define IO0PIN IOPIN
         #endif
         #ifndef FIO0PIN
            #define FIO0PIN FIOPIN
         #endif
         
         #ifndef IO0SET
            #define IO0SET IOSET
         #endif
         #ifndef FIO0SET
            #define FIO0SET FIOSET
         #endif
         #ifndef IO0CLR
            #define IO0CLR IOCLR
         #endif
         #ifndef FIO0CLR
            #define FIO0CLR FIOCLR
         #endif
      """ )
      
      self.C( """
         volatile unsigned int* mkt_gpio_pinsel( int N ){ 
            #ifdef PINSEL0
               if( N < 16 ) return & PINSEL0;
            #endif
            #ifdef PINSEL1
               if( N < 32 ) return & PINSEL1;
            #endif
            #ifdef PINSEL2
               if( N < 48 ) return & PINSEL1;
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      """ )
 
      self.Documentation( """
      
      #article gpio
      
         #anchor DIR, MK_GPIO_DIR
         #interface MK_GPIO_DIR
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin direction register
       
         The function MK_GPIO_DIR returns a pointer to the direction register
         for pin N.
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         In most ARM chips each pin has 1 bit in a DIR register.
         This bit controls, for pins that are specified as GPIO in the 
         #link PINSEL 
         register, whether the pin is an input or an output pin.
         In most ARM chip a 0 specifies the pin as input, a 1 specifies
         the pin as output, and the default (reset) state is input.
         (But an application should never rely on this reset state.)
      
         A mask for the bit within this register that controls pin N can be 
         calculated by shifting the value 1 left ( N % 32 ) times 
         (because each direction register controls 32 IO pins).
      
         Use this function only when you realy need direct access to a
         DIR register of a pin, and that pin is not a constant. The
         #link mkt_pin_configure 
         function provides an easier way to
         configure a pin as GPIO and set its direction. If it you need
         the DIR register and the pin number
         is a constant you could save code by using one of the DIR
         registers directly.
      """ )
      
      self.C_Header( """
         volatile /* "C" */ unsigned int* mkt_gpio_dir( int N );
      """ )
         
      self.C( """
      
         volatile unsigned int* mkt_gpio_dir( int N ){
            #if mkt_fast_gpio == 1
               #ifdef FIO0DIR
                  if( N < 32 ) return & FIO0DIR;
               #endif
               #ifdef FIO1DIR
                  if( N < 64 ) return & FIO1DIR;
               #endif
            #else
               #ifdef IO0DIR
                  if( N < 32 ) return & IO0DIR;
               #endif
               #ifdef IO1DIR
                  if( N < 64 ) return & IO1DIR;
                #endif
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      """ )
      
      self.Documentation( """      
      #article gpio
      
         #anchor PIN
         #interface MK_GPIO_PIN
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin value register
         
         The function MK_GPIO_PIN returns a pointer to the PIN (value) register
         for pin N. These registers 
         can be used to read the current level of pins that 
         are configured for input.
         For this to work the pin must be configured as GPIO (check 
         #link MK_GPIO_PINSEL) 
         and configured as input (check 
         #link MK_GPIO_DIR). 
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
      
         A mask for the bit within this register that contains the value for
         pin N can be calculated by shifting the value 1 left ( N % 32 ) times 
         (because each PIN register accesses 32 IO pins).
      
         Use this function only when you realy need direct access to a
         PIN register of a pin, and that pin is not a constant. The
         #link mkt_pin_read function provides an easier way to
         read the valueof a GPIO pin. If it you need
         a PIN register and the pin number
         is a constant you could save code by using one of the PIN
         registers directly.
      """ )
      
      self.C_Header( """
         volatile /* "C" */ unsigned int* mkt_gpio_pin( int N );
      """ )
         
      self.C( """
      
         volatile unsigned int* mkt_gpio_pin( int N ){
            #if mkt_fast_gpio == 1
               #ifdef FIO0PIN
                  if( N < 32 ) return & FIO0PIN;
               #endif
               #ifdef FIO1PIN
                  if( N < 64 ) return & FIO1PIN;
               #endif
            #else
               #ifdef IO0PIN
                  if( N < 32 ) return & IO0PIN;
               #endif
               #ifdef IO1PIN
                  if( N < 64 ) return & IO1PIN;
               #endif
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      """ )
      
      self.Documentation( """
      
      #article gpio
      
         #anchor SET, CLEAR
         #interface MK_GPIO_SET
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin set register
      
         #interface MK_GPIO_CLEAR
            #parameter N unsigned int 
               number of the IO pin
            #result V unsigned int *
               pointer to the pin clear register
      
         The functions MK_GPIO_SET and MK_GPIO_CLEAR return pointers to
         the SET and CLEAR registers for pin N.
         An invalid value for N will cause a call to the 
         #link mkt_fatal_error fatal error handler.
         These registers are used to set the value GPIO pins that 
         are configured as output pins.
         Writing a value to one of these registers affects only the 
         pins for which the corresponding bit is a 1: when writing to
         the SET register such pins are set (made high), when writing to
         the CLEAR register such pins are cleared (made low).
         Note that is makes it unnecessary to read these registers.
      
         For this to work the pin must be configured as GPIO (check 
         #link MK_GPIO_PINSEL) 
         and configured as output (check 
         #link MK_GPIO_DIR).
      
         Note that in order to clear a pin (make it low) you
         must write a value to the CLR register that has a 1 in
         the corresponding bit position. 
      
         Use these functions only when you realy need direct access to a
         SET register of a pin, and that pin is not a constant.
         The 
         #link mkt_pin_write 
         function provides an easier way to
         set the value of a GPIO pin. If it you need
         a SET or CLEAR register and the pin number
         is a constant you could save code by using the
         register directly.
         
         // int MK_GPIO_Mask( int N ); ?
         
         // example?
         
      """ )   
         
      self.C_Header( """
            volatile /* "C" */ unsigned int* mkt_gpio_set( int N );
            volatile /* "C" */ unsigned int* mkt_gpio_clr( int N );
      """ )
            
      self.C( """
      
         volatile unsigned int* mkt_gpio_set( int N ){
            #if mkt_fast_gpio == 1
               #ifdef FIO0SET
                  if( N < 32 ) return & FIO0SET;
               #endif
               #ifdef FIO1SET
                  if( N < 64 ) return & FIO1SET;
               #endif
            #else
               #ifdef IO0SET
                  if( N < 32 ) return & IO0SET;
               #endif
               #ifdef IO1SET
                  if( N < 64 ) return & IO1SET;
               #endif
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      
         volatile unsigned int* mkt_gpio_clr( int N ){
            #if mkt_fast_gpio == 1
               #ifdef FIO0CLR
                  if( N < 32 ) return & FIO0CLR;
               #endif
               #ifdef FIO1CLR
                  if( N < 64 ) return & FIO1CLR;
               #endif
            #else
               #ifdef IO0CLR
                  if( N < 32 ) return & IO0CLR;
               #endif
               #ifdef IO1CLR
                  if( N < 64 ) return & IO1CLR;
               #endif
            #endif
            mkt_fatal( mkt_fatal__invalid_pin_number );
            return 0;
         }
      """ ) 

      self.C( """      
         void /* "C" */ mkt_pin_direction( int N, int D ){
         
            // make it an input or output
            if( D == mkt_output ){
               *mkt_gpio_dir( N ) |= 1 << ( N % 32 );
            } else {
               *mkt_gpio_dir( N ) &= ~( 1 << ( N % 32 ));
            }
         }
         
         void /* "C" */ mkt_pin_configure( int N, int D ){
         
            // make the pin a GPIO pin
            mkt_pin_connect( N, 0 );
            
            // make it an input or output
            mkt_pin_direction( N, D );
         }
      
         void mkt_pin_write( int N, int V ){
            if( V ){
               *mkt_gpio_set( N ) = 1 << ( N % 32 );
            } else {
               *mkt_gpio_clr( N ) = 1 << ( N % 32 );
            }
         }
         
         unsigned char mkt_pin_read( int N ){ 
            return ((* mkt_gpio_pin( N )) & ( 1 << ( N % 32 ))) != 0;
         }
     
         void mkt_pin_connect( int N, int C ){
            volatile unsigned int *p;
            if( N < 32 + 16 ){
               p = mkt_gpio_pinsel( N );
               *p &=~ ( 3 << ( 2 * ( N % 16 )));
               *p |= ( C & 0x03 ) << ( 2 * ( N % 16 ));
            } else if( N < 32 + 26 ) {
               PINSEL2 &= ~0x04;
            } else {
               PINSEL2 &= ~0x08;
            }
         }

         void mkt_pin_set( int pin ){
            *mkt_gpio_set( pin ) = 1 << ( pin % 32 );
         }
         void mkt_pin_clear( int pin ){
            *mkt_gpio_clr( pin ) = 1 << ( pin % 32 );
         }
            
         
      """ )
                   
      self.C_Header( """
         // to simplify coding, it is sort-of assumed that 4 x 32 = 96 I/O's
         // are be present. The missing pointers are decleard as __mkt_dummy
         // to simplify the coding further, the MKT_IO... macro's are used,
         // which point to the legacy or the fast IO's, as configured
         extern unsigned volatile int __mkt_dummy;
         
         // this variable will be linked in to indicate that an invalid
         // pin number is used in a fixed-pin basic I/O macro call
         extern volatile unsigned int _MKT_INVALID_PIN_NUMBER;
         
         """ 
         + "\n" )  
         
      self.Assembler_And_C_Header(
         self.IO_Unification( "         " ).replace( "%NUMBER_OF_PINS", "64" ) )
         
      self.C( """
         unsigned volatile int __mkt_dummy;
      """ )   
         
      self.C_Header( """
               
         #define mkt_fixed_pin_input( pin ){ \\
            *MKT_GPIO_DIR( pin ) &= ~( 1 << ( pin % 32 )); }
         
         #define mkt_fixed_pin_output( pin ){ \\
            *MKT_GPIO_DIR( pin ) |= 1 << ( pin % 32 ); }
         
         #define mkt_fixed_pin_direction( pin, direction ) \\
            if( direction == mkt_output ){ \\
               mkt_fixed_pin_output( pin ); \\
            } else { \\
               mkt_fixed_pin_input( pin ); \\
            }
            
         #define mkt_fixed_pin_configure( pin, direction ){ \\
            *MKT_GPIO_SEL( pin ) &= ~( 3 << MKT_GPIO_SEL_OFFSET( pin )); \\
            mkt_fixed_pin_direction( pin, direction ); }
         
         #define mkt_fixed_pin_read( pin ) ( \\
            *MKT_GPIO_PIN( pin ) & ( 1 << ( pin % 32 )))
         
         #define mkt_fixed_pin_set( pin ){ \\
            *MKT_GPIO_SET( pin ) = ( 1 << ( pin % 32 )); }
         
         #define mkt_fixed_pin_clear( pin ){ \\
            *MKT_GPIO_CLR( pin ) = ( 1 << ( pin % 32 )); }
           
         #define mkt_fixed_pin_write( pin, value ) \\
            if( value ){ \\
               mkt_fixed_pin_set( pin ); \\
            } else { \\
               mkt_fixed_pin_clear( pin ); \\
            }         
      """ )
      
   def IO_Unification_Base( self, Text, Fast ):
      for Reg in [ "DIR", "SET", "CLR", "PIN", "SEL" ]:
         for Nr in [ "0", "1", "2", "3" ]:
            Name = "IO%s%s" % ( Nr, Reg )
            Fast_Name = "%s%s" % ( Fast, Name )
            Text.Add( "   #ifdef %s" % Fast_Name )
            Text.Add( "      #define MKT_%s %s" % ( Name, Fast_Name ))
            Text.Add( "   #else" )
            Text.Add( "      #define MKT_%s __mkt_dummy" % Name )
            Text.Add( "   #endif" )
            
   def IO_Unification_Pointer( self, Text ):
      for Name in [ "DIR", "SET", "CLR", "PIN" ]:
         Text.Add( "#define MKT_GPIO_%s( pin )( \\" % Name )
         Text.Add( "   ( pin >= %NUMBER_OF_PINS ) ? &_MKT_INVALID_PIN_NUMBER \\" )
         for Nr in [ 0, 1, 2, 3 ]:     
            Text.Add( "   : ( pin < ( %d + 32 )) ? &MKT_IO%d%s \\" 
               % ( Nr * 32, Nr, Name ))
         Text.Add( "   : &__mkt_dummy )" )
         
      Text.Add( "#define MKT_GPIO_SEL( pin )( \\" )
      Text.Add( "   ( pin >= %NUMBER_OF_PINS ) ? &_MKT_INVALID_PIN_NUMBER \\" )
      Text.Add( "   : ( pin >= 31 ) ? &MKT_IO2SEL \\" )
      for Nr in [ 0, 1, 2, 3 ]:
         Text.Add( "    : ( pin < ( %d + 16 )) ? &MKT_IO%dSEL \\" 
            % ( Nr * 16, Nr ))
      Text.Add( "    : &__mkt_dummy )" )
      
      Text.Add( "#define MKT_GPIO_SEL_OFFSET( pin )( \\" )
      Text.Add( "   ( pin < 32 ) ? (( pin % 16 ) * 2 ) \\" )
      Text.Add( "   : ( pin < 32 + 26 ) ? 3 \\" )
      Text.Add( "   : ( pin < 32 + 37 ) ? 2 \\" )
      Text.Add( "   : __mkt_dummy )" )
         
   def IO_Unification( self, Prefix ):      
      Text = Lines()
      Text.Add( "#if mkt_fast_gpio == 1" )
      self.IO_Unification_Base( Text, "F" )
      Text.Add( "#else" )
      self.IO_Unification_Base( Text, "" )
      Text.Add( "#endif" )
      self.IO_Unification_Pointer( Text )
      return Text.Plain_Text( Prefix )
      
class Peripherals_ARM:
   "ARM peripherals" 

   class Peripheral_ARM_VIC( Peripheral ):
      def __init__( self, 
         Base,  
         Nr     = None,
         Name   = "VIC", 
         Record = "VIC",
         Text   = "Vectored Interrupt Controller" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "IRQStatus"   , 0x000 ),
            Register( "FIQStatus"   , 0x004 ),
            Register( "RawIntr"     , 0x008 ),
            Register( "IntSelect"   , 0x00C ),
            Register( "IntEnable"   , 0x010 ),
            Register( "IntEnClr"    , 0x014 ),
            Register( "SoftInt"     , 0x018 ),
            Register( "SoftIntClear", 0x01C ),
            Register( "Protection"  , 0x020 ),
            Register( "VectAddr"    , 0x030 ),
            Register( "DefVectAddr" , 0x034 ),
            Register( "VectAddr0"   , 0x100 ),
            Register( "VectAddr1"   , 0x104 ),
            Register( "VectAddr2"   , 0x108 ),
            Register( "VectAddr3"   , 0x10C ),
            Register( "VectAddr4"   , 0x110 ),
            Register( "VectAddr5"   , 0x114 ),
            Register( "VectAddr6"   , 0x118 ),
            Register( "VectAddr7"   , 0x11C ),
            Register( "VectAddr8"   , 0x120 ),
            Register( "VectAddr9"   , 0x124 ),
            Register( "VectAddr10"  , 0x128 ),
            Register( "VectAddr11"  , 0x12C ),
            Register( "VectAddr12"  , 0x130 ),
            Register( "VectAddr13"  , 0x134 ),
            Register( "VectAddr14"  , 0x138 ),
            Register( "VectAddr15"  , 0x13C ),
            Register( "VectCntl0"   , 0x200 ),
            Register( "VectCntl1"   , 0x204 ),
            Register( "VectCntl2"   , 0x208 ),
            Register( "VectCntl3"   , 0x20C ),
            Register( "VectCntl4"   , 0x210 ),
            Register( "VectCntl5"   , 0x214 ),
            Register( "VectCntl6"   , 0x218 ),
            Register( "VectCntl7"   , 0x21C ),
            Register( "VectCntl8"   , 0x220 ),
            Register( "VectCntl9"   , 0x224 ),
            Register( "VectCntl10"  , 0x228 ),
            Register( "VectCntl11"  , 0x22C ),
            Register( "VectCntl12"  , 0x230 ),
            Register( "VectCntl13"  , 0x234 ),
            Register( "VectCntl14"  , 0x238 ),
            Register( "VectCntl15"  , 0x23C ),      
         ])
         
class Peripherals_NXP:
   "NXP (Philips) LPC peripherals"

   class Peripheral_Philips_WD( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "WD", 
         Record = "WATCHDOG",
         Text   = "Watchdog" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "MOD"         , 0x000 ),
            Register( "TC"          , 0x004 ),
            Register( "FEED"        , 0x008 ),
            Register( "TV"          , 0x00C ),      
         ])
         
   class Peripheral_Philips_Timer32A( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "T", 
         Record = "TIMER",
         Text   = "Timer (32 bit)" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "IR"          , 0x000 ),
            Register( "TCR"         , 0x004 ),
            Register( "TC"          , 0x008 ),
            Register( "PR"          , 0x00C ),
            Register( "PC"          , 0x010 ),
            Register( "MCR"         , 0x014 ),
            Register( "MR0"         , 0x018 ),
            Register( "MR1"         , 0x01C ),
            Register( "MR2"         , 0x020 ),
            Register( "MR3"         , 0x024 ),
            Register( "CCR"         , 0x028 ),
            Register( "CR0"         , 0x02C ),
            Register( "CR1"         , 0x030 ),
            Register( "CR2"         , 0x034 ),
            Register( "CR3"         , 0x038 ),
            Register( "EMR"         , 0x03C ),   
         ])
         
   class Peripheral_Philips_Timer32B( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "T", 
         Record = "TIMER",
         Text   = "Timer (32 bit)" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "IR"          , 0x000 ),
            Register( "TCR"         , 0x004 ),
            Register( "TC"          , 0x008 ),
            Register( "PR"          , 0x00C ),
            Register( "PC"          , 0x010 ),
            Register( "MCR"         , 0x014 ),
            Register( "MR0"         , 0x018 ),
            Register( "MR1"         , 0x01C ),
            Register( "MR2"         , 0x020 ),
            Register( "MR3"         , 0x024 ),
            Register( "CCR"         , 0x028 ),
            Register( "CR0"         , 0x02C ),
            Register( "CR1"         , 0x030 ),
            Register( "CR2"         , 0x034 ),
            Register( "CR3"         , 0x038 ),
            Register( "EMR"         , 0x03C ),   
            Register( "CTCR"        , 0x070 ),   
         ])
         
   class Peripheral_Philips_PWM( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "PWM", 
         Record = "PWM",
         Text   = "Pulse Width Modulator" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "IR"          , 0x000 ), 
            Register( "TCR"         , 0x004 ), 
            Register( "TC"          , 0x008 ), 
            Register( "PR"          , 0x00C ), 
            Register( "PC"          , 0x010 ), 
            Register( "MCR"         , 0x014 ), 
            Register( "MR0"         , 0x018 ), 
            Register( "MR1"         , 0x01C ), 
            Register( "MR2"         , 0x020 ), 
            Register( "MR3"         , 0x024 ), 
            Register( "MR4"         , 0x040 ), 
            Register( "MR5"         , 0x044 ), 
            Register( "MR6"         , 0x048 ), 
            Register( "PCR"         , 0x04C ), 
            Register( "LER"         , 0x050 ),   
         ])      
         
   class Peripheral_Philips_UART( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "U", 
         Record = "UART",
         Text   = "Universal Asynchronous Receiver Transmitter" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "RBR"         , 0x000 ),
            Register( "THR"         , 0x000 ),
            Register( "DLL"         , 0x000 ),
            Register( "IER"         , 0x004 ),
            Register( "DLM"         , 0x004 ),
            Register( "IIR"         , 0x008 ),
            Register( "FCR"         , 0x008 ),
            Register( "LCR"         , 0x00C ),
            Register( "MCR"         , 0x010 ),
            Register( "LSR"         , 0x014 ),
            Register( "MSR"         , 0x018 ),
            Register( "SCR"         , 0x01C ),
         ])
         
   class Peripheral_Philips_I2C( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "I2", 
         Record = "I2C",
         Text   = "I2C Interface" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "CONSET"      , 0x000 ),
            Register( "STAT"        , 0x004 ),
            Register( "DAT"         , 0x008 ),
            Register( "ADR"         , 0x00C ),
            Register( "SCLH"        , 0x010 ),
            Register( "SCLL"        , 0x014 ),
            Register( "CONCLR"      , 0x018 ),   
         ])
         
   class Peripheral_Philips_SPI( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "SP", 
         Record = "SPI",
         Text   = "Serial Peripheral Interface" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "CR"          , 0x000 ),
            Register( "SR"          , 0x004 ),
            Register( "DR"          , 0x008 ),
            Register( "CCR"         , 0x00C ),
            Register( "TCR"         , 0x010 ),
            Register( "TSR"         , 0x014 ),
            Register( "TOR"         , 0x018 ),
            Register( "INT"         , 0x01C ),
         ])
         
   class Peripheral_Philips_RTC( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "RTC", 
         Record = "RTC",
         Text   = "Real Time Clock" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "ILR"           , 0x000 ),
            Register( "CTC"           , 0x004 ),
            Register( "CCR"           , 0x008 ),
            Register( "CIIR"          , 0x00C ),
            Register( "AMR"           , 0x010 ),
            Register( "CTIME0"        , 0x014 ),
            Register( "CTIME1"        , 0x018 ),
            Register( "CTIME2"        , 0x01C ),
            Register( "SEC"           , 0x020 ),
            Register( "MIN"           , 0x024 ),
            Register( "HOUR"          , 0x028 ),
            Register( "DOM"           , 0x02C ),
            Register( "DOW"           , 0x030 ),
            Register( "DOY"           , 0x034 ),
            Register( "MONTH"         , 0x038 ),
            Register( "YEAR"          , 0x03C ),
            Register( "ALSEC"         , 0x060 ),
            Register( "ALMIN"         , 0x064 ),
            Register( "ALHOUR"        , 0x068 ),
            Register( "ALDOM"         , 0x06C ),
            Register( "ALDOW"         , 0x070 ),
            Register( "ALDOY"         , 0x074 ),
            Register( "ALMON"         , 0x078 ),
            Register( "ALYEAR"        , 0x07C ),
            Register( "PREINT"        , 0x080 ),
            Register( "PREFRAC"       , 0x084 ),
         ])
         
   class Peripheral_Philips_GPIO( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "IO", 
         Record = "GPIO",
         Text   = "General Purpose IO" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "PIN"          , 0x000 ),
            Register( "SET"          , 0x004 ),
            Register( "DIR"          , 0x008 ),
            Register( "CLR"          , 0x00C ),
         ])
         
   class Peripheral_Philips_F_GPIO( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "FIO", 
         Record = "FIO",
         Text   = "Fast General Purpose IO" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "DIR"          , 0x000 ),
            Register( "MASK"         , 0x010 ),
            Register( "PIN"          , 0x014 ),
            Register( "SET"          , 0x018 ),
            Register( "CLR"          , 0x01C ),
         ])   
         
   class Peripheral_Philips_PinConnect( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "PINSEL", 
         Record = "PINSEL",
         Text   = "Pin Connect Block" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
   #         Register( ""            , 0x000 ),
            Register( "0"           , 0x000 ),
            Register( "1"           , 0x004 ),
            Register( "2"           , 0x014 ),
         ])
         
   class Peripheral_Philips_DAC( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "DAC", 
         Record = "DAC",
         Text   = "DA converter Connect Block" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "R"           , 0x000 ),
         ])
         
   class Peripheral_Philips_ADC( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "AD", 
         Record = "ADC",
         Text   = "Analog to Digital Converter" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "CR"            , 0x000 ),
            Register( "GDR"           , 0x004 ),
            Register( "GSR"           , 0x008 ),
         ])
         
   class Peripheral_Philips_SSP( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "??", 
         Record = "SSP",
         Text   = "Synchronous Serial Peripheral" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
         ])
         
   class Peripheral_Philips_Timer16( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "T", 
         Record = "TIMER16",
         Text   = "Timer (16 bit)" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
         ])
         
   class Peripheral_Philips_MAM( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "MAM", 
         Record = "MAM",
         Text   = "Memory Accelerator Module" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "CR"          , 0x000 ),
            Register( "TIM"         , 0x004 ),
            Register( "MAP"         , 0x040 ),
         ])
        
   class Peripheral_Philips_PLL( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "PLL", 
         Record = "PLL",
         Text   = "Phase Locked Loop" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "CON"         , 0x000 ),
            Register( "CFG"         , 0x004 ),
            Register( "STAT"        , 0x008 ),
            Register( "FEED"        , 0x00C ),   
         ])
        
   class Peripheral_Philips_VPB( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "VPB", 
         Record = "VPB",
         Text   = "VPB Divider" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "DIV"         , 0x000 ),
         ])
        
   class Peripheral_Philips_PCON( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "PCON", 
         Record = "PCON",
         Text   = "Power Control" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
   #         Register( ""           , 0x000 ),
            Register( "P"          , 0x004 ),
         ])
        
   class Peripheral_Philips_EXT( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "EXT", 
         Record = "EXTI",
         Text   = "External Interrupts" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "INT"        , 0x000 ),
            Register( "WAKE"       , 0x004 ),   
         ])
        
   class Peripheral_Philips_SCS( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "SCS", 
         Record = "SCS",
         Text   = "System Control and Status" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( ""           , 0x000 ),
         ])
        
   class Peripheral_Philips_MEM( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "MEM", 
         Record = "MEM",
         Text   = "Memory mapping control" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "MAP"        , 0x000 ),
         ])
        
   class Peripheral_Philips_USB( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "USB", 
         Record = "USB",
         Text   = "USB device" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "DevIntSt"        , 0x000 ), 
            Register( "DevIntEn"        , 0x004 ), 
            Register( "DevIntClr"       , 0x008 ), 
            Register( "DevIntSet"       , 0x00C ), 
            Register( "CmdCode"         , 0x010 ), 
            Register( "CmdData"         , 0x014 ),
            Register( "RxData"          , 0x018 ), 
            Register( "TxData"          , 0x01C ), 
            Register( "RxPLen"          , 0x020 ), 
            Register( "TxPLen"          , 0x024 ), 
            Register( "Ctrl"            , 0x028 ), 
            Register( "DevIntPri"       , 0x02C ),          
            Register( "EpIntSt"         , 0x030 ), 
            Register( "EpIntEn"         , 0x034 ), 
            Register( "EpIntClr"        , 0x038 ), 
            Register( "EpIntSet"        , 0x03C ), 
            Register( "EpIntPri"        , 0x040 ),          
            Register( "ReEp"            , 0x044 ), 
            Register( "EpInd"           , 0x048 ), 
            Register( "MaxPSize"        , 0x04C ),                   
         ])      
         
   class Peripheral_Philips_USB_IntSt( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "USBIntSt", 
         Record = "USBIntSt",
         Text   = "USB device IntSt register",
          
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( ""                , 0x000 ),
         ])   
   
   class Peripheral_Philips_USB_DMA( Peripheral ):
      def __init__( self, Base, Nr = None, 
         Name   = "USB", 
         Record = "USB",
         Text   = "USB device" 
      ):   
         Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
            Register( "DevIntSt"        , 0x000 ), 
            Register( "DevIntEn"        , 0x004 ), 
            Register( "DevIntClr"       , 0x008 ), 
            Register( "DevIntSet"       , 0x00C ), 
            Register( "CmdCode"         , 0x010 ), 
            Register( "CmdData"         , 0x014 ),
            Register( "RxData"          , 0x018 ), 
            Register( "TxData"          , 0x01C ), 
            Register( "RxPLen"          , 0x020 ), 
            Register( "TxPLen"          , 0x024 ), 
            Register( "Ctrl"            , 0x028 ), 
            Register( "DevIntPri"       , 0x02C ),          
            Register( "EpIntSt"         , 0x030 ), 
            Register( "EpIntEn"         , 0x034 ), 
            Register( "EpIntClr"        , 0x038 ), 
            Register( "EpIntSet"        , 0x03C ), 
            Register( "EpIntPri"        , 0x040 ),          
            Register( "ReEp"            , 0x044 ), 
            Register( "EpInd"           , 0x048 ), 
            Register( "MaxPSize"        , 0x04C ),                   
            
            Register( "DMARst"          , 0x050 ),
            Register( "DMARClr"         , 0x054 ),                   
            Register( "DMARSet"         , 0x058 ),                   
            Register( "UDCAH"           , 0x080 ),                   
            Register( "EpDMASt"         , 0x084 ),                   
            Register( "EpDMAEn"         , 0x088 ),                   
            Register( "EpDMADis"        , 0x08C ),                   
            Register( "DMAIntSt"        , 0x090 ),                   
            Register( "DMAIntEn"        , 0x094 ),                   
            Register( "EoTIntSt"        , 0x0A0 ),                   
            Register( "EoTIntClr"       , 0x0A4 ),                   
            Register( "EoTIntSet"       , 0x0A8 ),                   
            Register( "NDDRintSt"       , 0x0AC ),                   
            Register( "NDDDRIntClr"     , 0x0B0 ),                   
            Register( "NDDRIntSet"      , 0x0B4 ),                   
            Register( "SysErrIntSt"     , 0x0B8 ),                   
            Register( "SysErrIntClr"    , 0x0BC ),                   
            Register( "SysErrIntSet"    , 0x0C0 ),                   
         ])      
     
class Peripheral_Atmel_USB( Peripheral ):
   "Atmel peripherals"

   def __init__( self, Base, Nr = None, 
      Name = "VIC", 
      Record = "VIC",
      Text = "Vectored Interrupt Controller" 
   ):   
      Peripheral.__init__( self, Name, Record, Text, Base, Nr, List = [
         Register( "IRQStatus"   , 0x000 ),
      ])      
      
def Target_Chips():
   Import_Class( Peripherals_ARM, Export = "*" )
   Import_Class( Peripherals_NXP, Export = "*" )

   class LPC( ARM ):
      "NXP LPC chips"
   
      def __init__( self, Name, ROM_size, RAM_size, Peripherals ):
         ram = RAM( 0x40000000, RAM_size )
         rom = ROM( 0, ROM_size )
         Target.__init__( self, Name, rom, ram, Peripherals )
         self.Chip_GCC_Flags = ""
         self.Chip_GCC_Flags += "-mcpu=arm7tdmi -mtune=arm7tdmi "
         self.Chip_GCC_Flags += "-mstructure-size-boundary=32 "
         
   class LPC210x( LPC ):
      def __init__( self, Name, ROM_size, RAM_size ):
         LPC.__init__( self, Name, ROM_size, RAM_size, Peripherals = [
            Peripheral_ARM_VIC(             0xFFFFF000 ),
            Peripheral_Philips_WD(          0xE0000000 ),
            Peripheral_Philips_Timer32A(    0xE0004000, 0 ),
            Peripheral_Philips_Timer32A(    0xE0008000, 1 ),
            Peripheral_Philips_UART(        0xE000C000, 0 ),
            Peripheral_Philips_UART(        0xE0010000, 1 ),
            Peripheral_Philips_I2C(         0xE001C000, 0 ),
            Peripheral_Philips_SPI(         0xE0020000 ),
            Peripheral_Philips_RTC(         0xE0024000 ),
            Peripheral_Philips_GPIO(        0xE0028000 ),
            Peripheral_Philips_PinConnect(  0xE002C000 ),
            Peripheral_Philips_ADC(         0xE0034000 ),
            Peripheral_Philips_I2C(         0xE005C000, 1 ),
            Peripheral_Philips_SSP(         0xE0068000, 0 ),
            Peripheral_Philips_Timer16(     0xE0070000, 2 ),
            Peripheral_Philips_Timer16(     0xE0074000, 3 ),
            Peripheral_Philips_MAM(         0xE01FC000 ),         
            Peripheral_Philips_PLL(         0xE01FC080 ),         
            Peripheral_Philips_VPB(         0xE01FC100 ),         
            Peripheral_Philips_PCON(        0xE01FC0C0 ),         
            Peripheral_Philips_EXT(         0xE01FC140 ),         
         ])
   
   LPC210x( Name = "LPC2101", ROM_size =   8 * Kb, RAM_size =  2 * Kb )
   LPC210x( Name = "LPC2102", ROM_size =  16 * Kb, RAM_size =  4 * Kb )
   LPC210x( Name = "LPC2103", ROM_size =  32 * Kb, RAM_size =  8 * Kb )
   
   class LPC210xx( LPC ):
      def __init__( self, Name, ROM_size, RAM_size ):
         LPC.__init__( self, Name, ROM_size, RAM_size, Peripherals = [
            Peripheral_ARM_VIC(             0xFFFFF000 ),
            Peripheral_Philips_WD(          0xE0000000 ),
            Peripheral_Philips_Timer32A(    0xE0004000, 0 ),
            Peripheral_Philips_Timer32A(    0xE0008000, 1 ),
            Peripheral_Philips_UART(        0xE000C000, 0 ),
            Peripheral_Philips_UART(        0xE0010000, 1 ),
            Peripheral_Philips_PWM(         0xE0014000 ),
            Peripheral_Philips_I2C(         0xE001C000 ),
            Peripheral_Philips_SPI(         0xE0020000 ),
            Peripheral_Philips_RTC(         0xE0024000 ),
            Peripheral_Philips_GPIO(        0xE0028000 ),         
            Peripheral_Philips_PinConnect(  0xE002C000 ),
            Peripheral_Philips_MAM(         0xE01FC000 ),         
            Peripheral_Philips_MEM(         0xE01FC040 ),         
            Peripheral_Philips_PLL(         0xE01FC080 ),         
            Peripheral_Philips_VPB(         0xE01FC100 ),         
            Peripheral_Philips_PCON(        0xE01FC0C0 ),         
            Peripheral_Philips_EXT(         0xE01FC140 ),         
         ])
   
   LPC210xx( Name = "LPC2104", ROM_size = 128 * Kb, RAM_size = 16 * Kb )
   LPC210xx( Name = "LPC2105", ROM_size = 128 * Kb, RAM_size = 32 * Kb )
   LPC210xx( Name = "LPC2106", ROM_size = 128 * Kb, RAM_size = 64 * Kb )
   
   class LPC213x( LPC ):
      def __init__( self, Name, ROM_size, RAM_size ):
         LPC.__init__( self, Name, ROM_size, RAM_size, Peripherals = [
            Peripheral_ARM_VIC(             0xFFFFF000 ),
            Peripheral_Philips_WD(          0xE0000000 ),
            Peripheral_Philips_Timer32B(    0xE0004000, 0 ),
            Peripheral_Philips_Timer32B(    0xE0008000, 1 ),
            Peripheral_Philips_UART(        0xE000C000, 0 ),
            Peripheral_Philips_UART(        0xE0010000, 1 ),
            Peripheral_Philips_PWM(         0xE0014000 ),
            Peripheral_Philips_I2C(         0xE001C000 ),
            Peripheral_Philips_SPI(         0xE0020000 ),
            Peripheral_Philips_RTC(         0xE0024000 ),
            Peripheral_Philips_GPIO(        0xE0028000 ),         
            Peripheral_Philips_GPIO(        0xE0028000, 0 ),         
            Peripheral_Philips_GPIO(        0xE0028010, 1 ),         
            Peripheral_Philips_PinConnect(  0xE002C000 ),
            Peripheral_Philips_MAM(         0xE01FC000 ),         
            Peripheral_Philips_PLL(         0xE01FC080 ),
            Peripheral_Philips_PLL(         0xE01FC080, 0 ),         
            Peripheral_Philips_PLL(         0xE01FC0A0, 1 ),         
            Peripheral_Philips_VPB(         0xE01FC100 ),         
            Peripheral_Philips_PCON(        0xE01FC0C0 ),         
            Peripheral_Philips_EXT(         0xE01FC140 ),         
            Peripheral_Philips_SCS(         0xE01FC1A0 ),         
            Peripheral_Philips_MEM(         0xE01FC040 ),         
            Peripheral_Philips_F_GPIO(      0x3FFFC000 ),         
            Peripheral_Philips_F_GPIO(      0x3FFFC000, 0 ),         
            Peripheral_Philips_F_GPIO(      0x3FFFC020, 1 ),         
         ])
   
   LPC213x( Name = "LPC2138", ROM_size = 512 * Kb, RAM_size = 32 * Kb )
   
   class LPC214x( LPC ):
      def __init__( self, Name, ROM_size, RAM_size ):
         LPC.__init__( self, Name, ROM_size, RAM_size, Peripherals = [
            Peripheral_ARM_VIC(             0xFFFFF000 ),
            Peripheral_Philips_WD(          0xE0000000 ),
            Peripheral_Philips_Timer32B(    0xE0004000, 0 ),
            Peripheral_Philips_Timer32B(    0xE0008000, 1 ),
            Peripheral_Philips_UART(        0xE000C000, 0 ),
            Peripheral_Philips_UART(        0xE0010000, 1 ),
            Peripheral_Philips_PWM(         0xE0014000 ),
            Peripheral_Philips_I2C(         0xE001C000 ),
            Peripheral_Philips_SPI(         0xE0020000 ),
            Peripheral_Philips_RTC(         0xE0024000 ),
            # Peripheral_Philips_GPIO(        0xE0028000 ),         
            Peripheral_Philips_GPIO(        0xE0028000, 0 ),         
            Peripheral_Philips_GPIO(        0xE0028010, 1 ),         
            Peripheral_Philips_PinConnect(  0xE002C000 ),
            Peripheral_Philips_DAC(         0xE006C000 ),
            Peripheral_Philips_MAM(         0xE01FC000 ),         
            # Peripheral_Philips_PLL(         0xE01FC080 ),         
            Peripheral_Philips_PLL(         0xE01FC080, 0 ),         
            Peripheral_Philips_PLL(         0xE01FC0A0, 1 ),         
            Peripheral_Philips_VPB(         0xE01FC100 ),         
            Peripheral_Philips_PCON(        0xE01FC0C0 ),         
            Peripheral_Philips_EXT(         0xE01FC140 ),         
            Peripheral_Philips_SCS(         0xE01FC1A0 ),         
            Peripheral_Philips_MEM(         0xE01FC040 ),         
            # Peripheral_Philips_F_GPIO(      0x3FFFC000 ),         
            Peripheral_Philips_F_GPIO(      0x3FFFC000, 0 ),         
            Peripheral_Philips_F_GPIO(      0x3FFFC020, 1 ),         
            Peripheral_Philips_USB_DMA(     0xE0090000 ),         
            Peripheral_Philips_USB_IntSt(   0xE01FC1C0 ),         
            Peripheral_Philips_ADC(         0xE0034000, 0 ),
            Peripheral_Philips_ADC(         0xE0060000, 1 ),
         ])
   
   LPC214x( Name = "LPC2148", ROM_size = 512 * Kb, RAM_size = 32 * Kb )   
         
   class AT91SAM7S( Target ):
      "Atmel AT91SAM7 chips"
   
      def __init__( self, Name, ROM, RAM ):
         return
   
         LPC.__init__( self, Name, ROM, RAM, Peripherals = [
            Peripheral_Atmel_Timer(  0xFFFA0000, 0 ),
            Peripheral_Atmel_Timer(  0xFFFA0000, 1 ),
            Peripheral_Atmel_Timer(  0xFFFA0000, 2 ),
            Peripheral_Atmel_USB(    0xFFFB0000 ),
            Peripheral_Atmel_TWI(    0xFFFB8000 ),
            Peripheral_Atmel_USART(  0xFFFC0000, 0 ),
            Peripheral_Atmel_USART(  0xFFFC4000, 1 ),
            Peripheral_Atmel_PWMC(   0xFFFCC000 ),
            Peripheral_Atmel_SSC(    0xFFFD4000 ),
            Peripheral_Atmel_ADC(    0xFFFD8000 ),
            Peripheral_Atmel_SPI(    0xFFFE0000 ),         
         ])
         
   AT91SAM7S( Name = "AT91SAM7S64",  ROM =  64 * Kb, RAM = 16 * Kb )
   AT91SAM7S( Name = "AT91SAM7S128", ROM = 128 * Kb, RAM = 32 * Kb )
   AT91SAM7S( Name = "AT91SAM7S256", ROM = 256 * Kb, RAM = 64 * Kb )
   AT91SAM7S( Name = "AT91SAM7S321", ROM =  32 * Kb, RAM =  8 * Kb )
   AT91SAM7S( Name = "AT91SAM7S32",  ROM =  32 * Kb, RAM =  8 * Kb )

   class PIC32MX( PIC32 ):
      "Microchip PIC32MX chips"
   
      def __init__( self, Name, ROM_size, RAM_size, Peripherals ):
         ram = RAM( 0x00000000, RAM_size )
         rom = ROM( 0x1D000000, ROM_size )
         Target.__init__( self, Name, rom, ram, Peripherals )
         self.Chip_GCC_Flags= "-mprocessor=32MX795F512L "
		 
   class PIC32MX7( PIC32MX ):
      "Microchip PIC32MX7 chips"
   
      def __init__( self, Name, ROM, RAM ):
   
         PIC32MX.__init__( self, Name, ROM, RAM, Peripherals = [        
         ])

   PIC32MX7( Name = "PIC32MX795F512L",  ROM =  512 * Kb, RAM = 32 * Kb )		 

Target_Chips()

Names = {}
   
Debug = 1
HTML = 2

def Error( Message, Line ):
   print( "*** [%d] %s : %s" % ( Line.Location.Line, Message, Line ))
  

def EncodeHTML( Line ):
   return Line.replace( "<", "&lt;" )
   
def EncodeRTF( Line ):
   return ( Line
      .replace( "\\", "\\\\" )
      .replace( "{",  "\\{"  )
      .replace( "}",  "\\}"  ))
      
   
def Make_HTML_Header( Text, Level ):
   if Level == 0:
      H = "1"
   elif Level == 1:
      H = "2"
   else:
      return "<b>%s</b><br>\n" % ( Text )
   return "<H%s>%s</H%s>\n" % ( H, Text, H )
   
def Make_HTML_Anchor( Name ):
   return '<A NAME="%s">' % Name
   
def MakeWebpage( Path, Element, Context, Result ):
   MakeDir( Path )
   if Context.OneFile:
      FileName = Context.FileName
      Name = Context.Title
   else:
      FileName = Element.ShortName
      Name = Element.Title
   File = open( os.path.join( Path, FileName + ".html" ), "w" )
   File.write( "<html><head>\n" )
   File.write( "<title>%s</title>\n" % Name )
#   File.write( "</head><body bgcolor=%s>\n" % Context.Page_Background )
   File.write( "</HEAD><BODY aLink=#558888 bgColor=#cccc99 link=#336666 vLink=#558888  BGCOLOR=#77CCBB>" )
   File.write( Make_HTML_Header( Name, 0 ))
   File.write( Result )
   File.write( "</body></html>\n" )
   File.close()
   
def Make_HTML_List( Content, Context ):
   return Content

def Make_HTML_List_Element( Content, Context ):
   Context.Add_Image( "redball.gif" )
   return (
      "\n<TABLE><TR><TD>&nbsp;" +
      "</TD><TD valign=top>"
         "<IMG BORDER=0 SRC=redball.gif></TD><TD>" +
      Content + 
      "\n</TD></TR></TABLE>"
   )
   
def Make_HTML_Indent_Element( Content, Indent ):
   return ((
      "\n<TABLE><TR><TD>&nbsp;" +
      "</TD><TD WIDTH=%d>"
      "</TD><TD>" +
      Content + 
      "\n</TD></TR></TABLE>" ) % Indent
   )

def Make_RTF_List( Content, Context ):
   return Content

def Make_RTF_List_Element( Content, Context ):
   # wovo
   return Content
   
class Make_Context:

   def __init__( self, 
      Documentation, 
      Images, 
      Destination, 
      FileName, 
      Title
   ):
      self.Documentation = Documentation
      self.Images = Images
      self.Destination = Destination
      self.Page_Background = "FFFFF"
      self.Literal_Background = "EEEEEE" 
      self.Literal_Indent = 20
      self.Literal_Margin = 10
      self.Literal_Border = 1
      self.Pictures = []
      self.OneFile = ( FileName != None )
      self.FileName = FileName
      self.Title = Title
      
   def Add_Image( self, Picture ):
      if not Picture in self.Pictures:
         Source = os.path.join( self.Images, Picture )
         self.Pictures.append( Picture )    
         try:
            MakeDir( self.Destination )
            shutil.copy( Source, self.Destination )
         except:
            Warning( "could not copy image file %s" % Picture )
      
class Element:

   def __init__( self, Header, Lines, Ignore = "" ):
      self.Body = []
      if Header == None:
         self.Header = One_Line( "" )
      else:
         self.Header = One_Line( 
            Header.Text.replace( Ignore, "" ), 
            Header.Location )
      self.Lines = Lines
      self.Empty = 0
      self.Anchors = []
      self.Indexes = []
   
   def Append( self, New ):
      if not New.Empty:
         self.Body.append( New )
            
   def MakeHTML( self, Context ):
      Result = ""
      for Item in self.Body:
         Result += Item.MakeHTML( Context )
      return Result   
      
   def MakeRTF( self, Context ):
      Result = PyRTF.Paragraph()
      for Item in self.Body:
         Result.append( Item.MakeRTF( Context ))
      return Result                  
         
class Empty_Element( Element ):
   def __init__( self ):
      Element.__init__( self, One_Line(""), Lines())
      self.Empty = 1      
      
def Is_Start( Line, Strip, Within, End, First ):
   if First != None:
      if First.Text.strip().startswith( "#index" ):
         return 1
   if End != None:
      return Strip.startswith( End )
   if Within:
      return ( Strip == "" ) or (
         ( Strip.startswith( '#' ) and not (
            Strip.startswith( "#break" ) 
            or Strip.startswith( "#link" ) 
            or Strip.startswith( "#url" ) 
            or Strip.startswith( "#image" ) 
            or Strip.startswith( "#related" ) 
            or Strip.startswith( "#parameter" ) 
            or Strip.startswith( "#result" ) 
         ))
      )
   else:
      return ( 
         Strip.startswith( '#article' )
         or Strip.startswith( '#faq' ))
      
def Add_Container_References( Container, Strip ):
   if Strip.startswith( "#index" ):
      New = Empty_Element()
      for Entry in Strip.replace( "#index", '' ).split( "," ):
         New.Indexes.append( Entry.strip() )
      Container.Indexes += New.Indexes
   else: #anchor
      New  = Element_Anchors( One_Line( Strip.replace( "#anchor", '' )), [] )
      Container.Anchors += New.Anchors
   return New
      
def Add_Elements( Container, Source, Within = 1 ):
      First = None
      Buffer = Lines()
      End = None
      Last = ""
      for ALine in Source.Lines:
         # Line = ALine.Text.replace( "\n", "" )
         # print( ALine.Nr_And_Text())
         Strip = ALine.Text.strip()
         # print( Strip )
         if Strip.startswith( "//" ):
            pass # ignore comment lines
         elif Strip[-2:] == "\\\\":
            Last += Strip[:-2]
         else:
            if Last != "":
               Strip = Last + Strip
               Line = Last + ALine.lstrip()
               Last = ""
               #print "Line [%s]" % Line
               #print "Strip [%s]" % Strip
            if Within and ( 
               Strip.startswith( "#anchor" )
               or Strip.startswith( "#index" )
            ):
               Add_Container_References( Container, Strip )
            elif Is_Start( ALine.Text, Strip, Within, End, First ):
               if 0: print( 
                  "is start line[%s] strip[%s] within[%s]" 
                  % (Line, Strip, Within))
               if First != None:
                  #print "First [%s]" % First
                  #print "0"
                  Container.Add_Element( First, Buffer )
                  #print "1"
               First = ALine
               Buffer = Lines()
               End = None
               if Strip.startswith( "#literal" ):
                  End = "#end literal"
               if Strip.startswith( "#code" ):
                  End = "#end code"               
               if Strip.startswith( "#list" ):
                  End = "#end list"               
            else:
               Buffer.Add_Line( ALine )   
      if 0: # debug
         print( First, Buffer )
      #print( "2" )
      # don't forget the last one!
      if First != None:
         Container.Add_Element( First, Buffer )
         
class Element_Line( Element ):

   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.Line = Header.Text.strip()
      for Line in Lines.Lines:
         self.Line += " " + Line.Text.strip()
      
   def MakeHTML( self, Context ):      
      return EncodeHTML( self.Line )
         
   def MakeRTF( self, Context ):      
      return self.Line + " \n"
         
class Element_Header( Element ):

   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.Line = Header.Text.replace( "#header", "", ).strip()
      self.ShortName = self.Line.split()[ 0 ]
      self.Title = self.Line.replace( self.ShortName, "", 1 ).strip() 
      if self.Title == "":
         self.Title = self.ShortName
      self.Anchors.append( self.ShortName )
      Names[ self.ShortName ] = self.Title
      
   def MakeHTML( self, Context ):      
      Result = ""
      Result += "<P><HR></P>"
      Result += Make_HTML_Anchor( self.ShortName )
      Result += Make_HTML_Header( EncodeHTML( self.Title ), 1 )
      return Result
         
   def MakeRTF( self, Context ):      
      return self.Line + " \n"
         
class Element_Subheader( Element ):

   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.Line = Header.Text.replace( "#subheader", "", ).strip()
      self.Paragraph = Element_Paragraph( 
         One_Line( "", Header.Location ),
         Lines, Format = 0 )      
      
   def MakeHTML( self, Context ):      
      Result = "<P>\n"
      Result += Make_HTML_Header( EncodeHTML( self.Line ), 2 )
      Result += Make_HTML_Indent_Element( self.Paragraph.MakeHTML( Context ), 20 )
      Result += "</P>\n"
      return Result
         
   def MakeRTF( self, Context ):      
      return self.Line + " \n"
         
class Element_Break( Element ):

   def __init__( self, Header, Bulk ):
      Element.__init__( self, Header, Lines )
      self.Line = Header.Text.strip()
      for Line in Bulk.Lines:
         self.Line += " " + Line.Text.strip()
      
   def MakeHTML( self, Context ):      
      return "&nbsp;<BR>"
         
   def MakeRTF( self, Context ):      
      return self.Line + " \n"
         
class Element_Anchors( Element ):

   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.Names = Header.Text.replace( ",", "").split()
      self.Anchors = self.Names
      
   def MakeHTML( self, Context ):      
      Result = ""
      for Name in self.Names:
         Result += '<A Name="%s">\n' % Name
      return Result
         
   def MakeRTF( self, Context ):      
      return self.Line + " \n"
         
class Element_URL( Element ):

   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.Line = Header.Text.replace( "#url", "" ).strip()
      Split = self.Line.strip().split()
      if len( Split ) > 1:
         self.Link = Split[0]
         self.Name = self.Line.replace( self.Link, "" ).strip()
         self.After = ''
      else:
         self.Link, self.After = Split_Link( self.Line, Url = 1 )
         self.Name = self.Link
        
   def MakeHTML( self, Context ):      
      return '<A HREF="%s">%s</A>%s' % ( self.Link, self.Name, self.After )
         
   def MakeRTF( self, Context ):      
      return (
         '{\field{\*\fldinst{HYPERLINK "%s" }}{\fldrslt{\cf2\\ul "%s"}}}'
         % ( self.Link, self.Name ))
         
class Element_Link( Element ):

   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.Line = Header.Text.replace( "#link", "" ).strip()
      self.Target = self.Line.split()[0]
      self.Name = self.Line.replace( self.Target, "", 1 )
      self.Target, self.After = Split_Link( self.Target )
      self.Name, self.After2 = Split_Link( self.Name )
      
   def CheckLink( self, Context ):
      if not self.Target in Context.List.has:
         Error( self.Start, "dead link", self.Line )
      
   def MakeHTML( self, Context ):   
      Target_Name = Context.Documentation.Anchors.get( self.Target, None )
      if Target_Name == None:
         Warning( "unknown link [%s]" % self.Target )
         return self.Name
      else:
         Target = Context.Documentation.Articles.get( Target_Name )
         # this does not work any more...
         # self.CheckLink( Context )
         if self.Name == '':
            self.Name = Names.get( self.Target, Target.Title )
         if Context.OneFile:
            Link = "#" + self.Target
         else:
            Link = Target.ShortName + ".html#" + self.Target
         return '<A HREF="%s">%s</A>%s%s' % \
            ( Link, self.Name, self.After, self.After2 )
            
   def MakeRTF( self, Context ):   
      # wovo
      return "{" + self.Line + "}"      
         
class Element_Index( Element ):

   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.Links = []
      for Link in Header.replace( "#index", "" ).split( "," ):
         self.Links.append( Link.strip() )
     
   def MakeHTML( self, Context ):      
      Result = ''
      return Result
      
   def MakeRTF( self, Context ):      
      Result = ''
      return Result
      
class Element_List( Element ):
      
   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      Add_Elements( self, Lines )
      
   def Add_Element( self, First, Buffer ):
      New = Make_Element( First, Buffer )
      if not New.Empty:
         self.Body.append( New )

   def MakeHTML( self, Context ):      
      Result = ''
      if 0: # debug
         print( self.Body )
      for Part in self.Body:
         Result += Make_HTML_List_Element( Part.MakeHTML( Context ), Context)
      Result = (
         ( "<!-- list [%4d][%s] -->\n"
            % ( self.Header.Location.Line, self.Header ))
         + Make_HTML_List( Result, Context ))
      return Result            
               
   def MakeRTF( self, Context ):      
      Result = PyRTF.Paragraph()
      for Part in self.Body:
         Result.append( 
            Make_RTF_List_Element( Part.MakeRTF( Context ), Context))
      return Make_RTF_List( Result, Context )
                     
class Element_Parameter( Element ):

   def __init__( self, Header, Bulk, Nr ):
      Element.__init__( self, Header, Bulk )
      self.Register = "R%d" % Nr
      self.Name = Header.Text.split()[ 1 ]
      self.Type = Header.Text \
         .replace( "#result", "" ) \
         .replace( "#parameter", "" ) \
         .replace( self.Name, "" ) \
         .strip()
      #try:
      self.Text = Make_Line_Element( One_Line( "" ), Bulk )       
      #except:
      #   self.Text = Make_Line_Element( One_Line( "{error}" ) , Lines() )
      #   Error( "elements missing", Header )
      
   def MakeHTML( self, Context, Assembler, Separator = None ):      
      Result = ''
      Text = self.Text.MakeHTML( Context )     
      if Assembler:
         Result = "   %s : %-10s %-20s // %s" % \
            ( self.Register, self.Name, "(" + self.Type + ")", Text )
      else:
         Result = "   %s %s%s // %s" % \
            ( self.Type, self.Name, Separator, Text )
      return Result
            
class Element_Interface( Element ):

   def __init__( self, Header, Body ):
      Element.__init__( self, Header, Body, Ignore = "#interface" )
      self.Parameters = []
      self.Summary = Empty_Element()
      self.Result = None
      self.Nr = 0
      Bulk = Lines()
      #print "=============="
      #print Header
      #print Lines
      for Line in Body.Lines:
         if( 
            Line.Text.strip().startswith( "#parameter" )
            or Line.Text.strip().startswith( "#result" )
         ):
            self.Add_Bulk( Bulk )
            Bulk = Lines()
         Bulk.Add_Line( Line )
      self.Add_Bulk( Bulk )
      
   def Add_Bulk( self, Bulk ):
      if Bulk.Lines != []:
         #print "----------------"
         #print Bulk
         First = Bulk.Lines[ 0 ]
         Rest = Lines_From_Lines( Bulk.Lines[ 1: ] )
         if Bulk.Lines[ 0 ].Text.strip().startswith( "#parameter" ):
            self.Parameters.append( Element_Parameter( First, Rest, self.Nr ))
            self.Nr = self.Nr + 1
         elif Bulk.Lines[ 0 ].Text.strip().startswith( "#result" ):
            self.Result = Element_Parameter( First, Rest, 0 )
         else:
            self.Summary = Element_Line( First, Rest )
      
   def MakeHTML2( self, Context, Assembler ):      
      Result = ""
      if Assembler:
         Result += "// %s (ARM assembler)\nsubroutine %s" % ( 
            self.Summary.MakeHTML( Context ).strip(), 
            self.Header.Text.strip() )
         if self.Parameters == []:
            Result += "   no parameters"
         else:
           for Parameter in self.Parameters:
               Result += "\n" + Parameter.MakeHTML( Context, Assembler )
         if self.Result != None:
            Result += "\nreturns:\n"
            Result += self.Result.MakeHTML( Context, Assembler )          
      else:
         Result += (
            "// %s (C, C++)\n" 
            % self.Summary.MakeHTML( Context ).strip()
         )
         if self.Result == None:
            Result += "void"
         else:
            Result += self.Result.Type
         Result += " %s(" %  self.Header.Text.strip()
         if self.Parameters == []:
            Result += " void );\n"
         else: 
            for Parameter in self.Parameters:
               Separator = " "
               Result += "\n"
               Result += Parameter.MakeHTML( Context, Assembler, Separator )
               Separator = ","
            Result += "\n);"
            
      Result = (
         ( "<!-- interface [%4d][%s] -->\n"
            % ( self.Header.Location.Line, self.Header ))
         + "<TABLE><TR><TD WIDTH=10></TD><TD>\n"
         + "<TABLE CELLPADDING=10 BORDER=1><TD BGCOLOR=EEEEEE><CODE><PRE>\n"
         + Result
         + "</PRE></CODE></TD></TR></TABLE>\n" 
         + "</TD></TR></TABLE>\n")
      Result = Result.\
         replace( "<CODE>\n", "<CODE>" ).\
         replace( "\n</CODE>", "</CODE>")
            
      return Result
            
   def MakeHTML( self, Context ):      
      return (
         self.MakeHTML2( Context, 0 ) 
         + self.MakeHTML2( Context, 1 ))
            
class Element_Paragraph( Element ):

   def __init__( self, Header, Bulk, Format = 1 ):
      Element.__init__( self, Header, Bulk )
      self.Empty = 1
      self.Format = Format
      for Line in [ 
         One_Line( Header.Text.replace( "#paragraph", "" ).strip())
      ] + Bulk.Lines:
         Strip = Line.Text.strip()
         if Strip != "":
            self.Append( Make_Line_Element( One_Line( Strip ), Lines()))
            self.Empty = 0         
      
   def MakeHTML( self, Context ):      
      Result = ''
      for Part in self.Body:
         Result = Result + Part.MakeHTML( Context ) + '\n'
      if self.Format:
         Result = "<P>\n" + Result + "</P>\n"
      Result = (
         ( "<!-- paragraph [%4d][%s] -->\n"
            % ( self.Header.Location.Line, self.Header ))
         + Result )
      return Result
            
   def MakeRTF( self, Context ):      
      # wovo
      Result = PyRTF.Paragraph()
      for Part in self.Body:
         Result.append( Part.MakeRTF( Context ))
      return Result

class Element_Literal( Element ):
   
   def __init__( self, Header, Bulk ):
      Body = Lines()
      if Bulk.Lines != []:
         N = Indent_Count( Bulk.Lines[ 0 ].Text )
         for Line in Bulk.Lines:
            X = Indent_Count( Line.Text )
            if X < N:
               N = X
      for Line in Bulk.Lines:
         Body.Add( Line.Text[ N: ] )
      Element.__init__( self, Header, Body )
      self.File_Name = None
      H = Header.Text.replace( "#code", "" ).strip()
      if H.startswith( "file" ):
         self.File_Name = H.replace( "file", "" ).strip()
               
   def Export( self, Context ):
      if self.File_Name != None:
         self.Lines.Write( os.path.join( 
            Context.Destination, self.File_Name ))
      
   # on screen an ugly empty line is appended after the text, but
   # at least in IE this line is not printed on paper!
   def MakeHTML( self, Context ):      
      self.Export( Context )
      Result = ''
      L_Margin = "&nbsp;"
      R_Margin = "&nbsp;"
      for Line in self.Lines.Lines:
         Result = Result + L_Margin + EncodeHTML( Line.Text ) + R_Margin + '\n'
      Caption = ""
      if self.File_Name != None:
         Caption = ( '<TR><TD BGCOLOR=CCCCCC ALIGN=CENTER>' +
            '<A HREF="%s">%s</A></TD></TR>'
               % ( self.File_Name, self.File_Name ))
      Result = (
         ( "<!-- literal [%4d][%s] -->\n"
            % ( self.Header.Location.Line, self.Header ))
#         + "<TABLE><TR><TD WIDTH=40></TD><TD>\n"
         + "<TABLE><TR><TD></TD><TD>\n"
         + "<TABLE border=1 cellpadding=1 cellspacing=0><TR><TD BGCOLOR=EEEEEE><CODE><PRE>\n"
         + Result
         + "</PRE></CODE></TD></TR>"
         + Caption
         + "</TABLE>\n" 
         + "</TD></TR></TABLE>\n")
      Result = Result.\
         replace( "<CODE>\n", "<CODE>" ).\
         replace( "\n</CODE>", "</CODE>")
      return Result
      
   def MakeRTF( self, Context ):      
      Result = ''
      for Line in self.Lines:
         Result = Result + EncodeRTF( Line ) + '\n'
      return Result

class Element_Image( Element ):

   def __init__( self, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.Line = Header.Text.replace( "#image", "" ).strip()
      Split = self.Line.split()
      self.Align = ""
      if Split[ 0 ] in [ 
         "top", "abstop", 
         "middle", "absmiddle", 
         "bottom", "absbottom"
      ]:
         self.Align = ( "align=%s" % Split[ 0 ] )
         Split = Split[1:]
      self.Target = Split[ 0 ]
      self.Name = self.Target
      
   def MakeHTML( self, Context ):      
      #Result = ''
      #for Part in self.Body:
      #   Result = Result + Part.MakeHTML( Context ) + '\n'
      Context.Add_Image( self.Target )    
      Result = "<IMG SRC=\"%s\">\n" % self.Target
      return Result
            
   def MakeHTML( self, Context ):      
      Context.Add_Image( self.Target )    
      Result = "<IMG %s SRC=\"%s\">\n" % ( self.Align, self.Target )
      return Result
      
def Make_Line_Element( Header, Lines = [] ):      
   HeaderStrip = Header.Text.strip()
   
   if 0: # debug
      print("line {%s}" % HeaderStrip )
      
   if not HeaderStrip.startswith( "#" ):
      return Element_Line( Header, Lines )
      
   elif HeaderStrip.startswith( "#break" ):
      return Element_Break( Header, Lines )
      
   elif HeaderStrip.startswith( "#url" ):
      return Element_URL( Header, Lines )
      
   elif HeaderStrip.startswith( "#link" ):
      return Element_Link( Header, Lines )
      
   elif HeaderStrip.startswith( "#image" ):
      return Element_Image( Header, Lines )
      
   elif HeaderStrip.startswith( "#paragraph" ):
      return Element_Paragraph( Header, Lines )
      
   elif HeaderStrip.startswith( "#related" ):
      return Empty_Element()
            
   else:   
      Warning( "unknown text element [%s]" % HeaderStrip )
      
   return Element( 
      One_Line( "{unknown line element}" + HeaderStrip ), 
      Lines )
            
def Make_Element( Header, Lines ):
   HeaderStrip = Header.Text.strip()
   if not HeaderStrip.startswith( "#" ):
      return Element_Paragraph( Header, Lines )
      
   elif HeaderStrip.startswith( "#example" ):
      pass
      
   elif HeaderStrip.startswith( "#paragraph" ):
      return Element_Paragraph( Header, Lines )
      
   elif HeaderStrip.startswith( "#interface" ):
      return Element_Interface( Header, Lines )
      
   elif HeaderStrip.startswith( "#literal" ):
      return Element_Literal( Header, Lines )
      
   elif HeaderStrip.startswith( "#header" ):
      return Element_Header( Header, Lines )
      
   elif HeaderStrip.startswith( "#subheader" ):
      return Element_Subheader( Header, Lines )
      
   elif HeaderStrip.startswith( "#code" ):
      return Element_Literal( Header, Lines )
      
   elif HeaderStrip.startswith( "#index" ):
      return Element_Index( Header, Lines )

   elif HeaderStrip.startswith( "#list" ):
      return Element_List( Header, Lines )
      
   elif HeaderStrip.startswith( "#end" ):
      return Empty_Element()
      
   else:
      Error( "unknown text element", Header )
   
   return Element( One_Line( 
      "{unknown text element}" + Header.Text), Lines )
       
class Main_Element( Element ):

   def __init__( self, Marker, Header, Lines ):
      Element.__init__( self, Header, Lines )
      self.ShortName = "<mising>"
      try:
         self.ShortName = Header.Text.split()[1]
      except:
         # print( Header.Text.split())
         Warning( "missing header elements", Header.Location )
      self.Anchors.append( self.ShortName )
      self.Title = ( Header.Text
         .replace( Marker, '' )
         .replace( self.ShortName, "", 1 )
         .strip())
      if self.Title == "":
         self.Title = self.ShortName
      Add_Elements( self, Lines )
      # print( "\n=====\n", self.Body )
      
   def Add_Ready_Element( self, New ):
      self.Anchors.extend( New.Anchors )
      self.Indexes.extend( New.Indexes )
      if not New.Empty:
         self.Body.append( New )
      
   def Add_Element( self, First, Buffer ):
      New = Make_Element( First, Buffer )
      self.Add_Ready_Element( New )
            
class Documentation:

   def __init__( self, Source ):
      self.Articles  = {}
      self.Faqs      = {}
      self.Anchors   = {}
      self.Indexes   = {}
      Add_Elements( self, Source, Within = 0 )
      
   def Add_Element( self, First, Lines ):
      # print( "found main element [%s]" % First )
      #if First.startswith( '#section' ) or First.startswith( '#end' ):
      #   pass
      if First.Text.strip().startswith( '#article' ):
         self.Add_Item( 
            Main_Element( "#article", First, Lines ),
            self.Articles )
      elif First.Text.strip().startswith( '#faq' ):
         self.Add_Item( 
            Main_Element( "#faq", First, Lines ),
            self.Faqs )
      else:
         Error( Nr, "unknown main section", First )
         
   def Add_Item( self, Item, List ):
   
      # add the current item to the item list of its container,
      # append to an alrady-existing element with the same name
      Base = List.get( Item.ShortName, None )
      if Base != None:
         Base.Body += Item.Body
         List[ Item.ShortName ] = Base
      else:
         List[ Item.ShortName ] = Item         
      
      # remember the current Item name for each values in its
      # Item.Anchors list. each Anchor should be unique
      for Anchor in Item.Anchors:
         if self.Anchors.get( Anchor, None ) != None:
            if Anchor != Item.ShortName:
               print( "duplicated anchor [%s]" % Anchor )
               # Error( Item.Start, "duplicated anchor [%s]" % Anchor, "" )
         else:
            self.Anchors[ Anchor ] = Item.ShortName
            
      # add the current Item to each Indexes entry 
      # that appears the Item.Indexes list
      for Index in Item.Indexes:
         # print self.Indexes, Index
         self.Indexes[ Index ] = \
            self.Indexes.get( Index, [] ) + [ Item.ShortName ]
         
   def MakeTOC( self, Context ):
      Contents = Lines()
      Contents.Add( "#list" )
      for Name in Context.List:
         # print( "   ", Name )
         ShortName = self.Anchors.get( Name, None )
         if ShortName == None:
            Warning( "unknown content item [%s]" % Name, "" )
         else:
            Contents.Add( "#paragraph #link %s" % ShortName )
      Contents.Add( "#end list" )
      # print( Contents.Text_Only())
      return Main_Element( 
         "#article", One_Line( "#article contents Contents" ), Contents )
      
   def MakeContextList( self, Context, List ):
      if List == None:
         Context.List = []
         for Name, Item in self.All.items():
            Context.List.append( Item.ShortName )
      else:
         Context.List = List            
      
   def MakeHTML( self, 
      Path, 
      Name    = None, 
      List    = None, 
      Context = None 
   ):
      if Context == None:
         Context = Make_Context( self, "images", Path, 'index', Name )
         self.MakeContextList( Context, List )
      BigResult = ''
      Separator = ''
      Colofon = """
         %s last modified %s
         <BR>
         homepage : <A HREF="http://www.voti.nl/mkt">
         http://www.voti.nl/mkt</A>
         <!--
         <BR>
         this manual on-line :  
         <A HREF="http://www.voti.nl/mkt/manual">
         http://www.voti.nl/mkt/manual</A>
         -->
         <P>
         <HR>
         <H2>Contents</H2>
         """ % ( Global.Version, Global.Modified )
      for ShortName in Context.List:
         Item = self.Articles.get( ShortName, None )
         if Item == None:
            Warning( "Item %s in list but not found" % ShortName, "" )
         else:
            Result = Item.MakeHTML( Context )
            if Context.OneFile:
               BigResult += ( 
                  "<P></P><HR><HR>\n" +
                  ( '<A NAME="%s">' % Item.ShortName ) + 
                  Make_HTML_Header( Item.Title, 0 ))                  
               BigResult += Result   
            else:
               MakeWebpage( Path, Item, Context, Result )
      TOC = self.MakeTOC( Context ).MakeHTML( Context )
      # print( TOC )
      if Context.OneFile:
         BigResult = Colofon + TOC + BigResult
         MakeWebpage( Path, TOC, Context, BigResult )
      else:
         MakeWebpage( Path, Colofon + TOC, Context, Index )            
      
   def MakeRTF( self, FileName, List = None, Context = None ):
      Result = PyRTF.Document()   
      if Context == None:
         Context = Make_Context( self, "images", None, None )
         self.MakeContextList( Context, List )
         Context.StyleSheet = Result.StyleSheet
      Separator = None
      for Name in Context.List:
         Item = self.All[ Name ]
         
         Section = PyRTF.Section()
         if Separator != None:
            Section.append( "\page " )            
         Separator = "\page "
         
         Title = PyRTF.Paragraph( Context.StyleSheet.ParagraphStyles.Heading1 )
         Title.append( Item.Name )
         Section.append( Title )
    
         Body = PyRTF.Paragraph( Context.StyleSheet.ParagraphStyles.Normal )
         Body.append( Part )
         Section.append( Body )
         
         Result.Sections.append( Section )
      Renderer = PyRTF.Renderer()      
      Renderer.Write( Result, file( FileName, "w" ))
         
   def MakeDoc( self ):
      # this list is not actuive!
      List = [
         "introduction",
         "installation",
         "start-with-devcpp",
         "ea-configuration",
         "tools",
         "ea-file-format",
         "ea-chips",
         "ea-boards",
         "ea-startup",
         "linker-script",
         "exception-vectors",
         "memory-sections",
         "run-from-RAM",
         "busy-waiting",
         "fatal-error-handling",
         "memory-allocation",
         "stacks",
         "interrupts",
         "gpio",
         "leds",
         "char-lcd",
         "uart",
#         "char-format",
      ]
      self.MakeHTML( "documentation", "MicroKit (mkt)", List )
      if 0:
         self.MakeRTF( "EasyARM.rtf", List )
         
class Mkt_Library:
   "the mkt library sources"
   
   def __init__( self, Configuration ):
      self.Configuration = Configuration
      self.List = []
      for Section in [
         Lib_Sections,
         Lib_Vectors,
         Lib_Startup,
         Lib_Run_From_RAM,
      ]:
         self.List.append( Section( Configuration))
      
            
   def Header( self, File ):
      Text = Lines( Write_Name = File )
      for Part in self.List:
         Text.Add( "//asm" )
         Text.Add( "#ifdef __ASSEMBLER__" )
         Text.Add( Part.Get_Assembler_Header())
         Text.Add( "#endif" )
         Text.Add( "//C" )
         Text.Add( Part.Get_C_Header())
         Text.Add( "//CPP" )
         Text.Add( Part.Get_CPP_Header())
      return Text

   def Asm( self, File ):
      Text = Lines( Write_Name = File )
      for Part in self.List:
         Text.Add( Part.Get_Asm())
      return Text

   def C( self, File ):
      Text = Lines( Write_Name = File )
      for Part in self.List:
         Text.Add( Part.Get_C())
      return Text

   def CPP( self, File ):
      Text = Lines( Write_Name = File )
      for Part in self.List:
         Text.Add( Part.Get_CPP())
      return Text
      
def mkt_Chip( Chip_Name, Configuration = None, Python = 0 ):
   if 0:
      print( "chip-name", Chip_Name )
   for Chip in Chips:
      if 0:
         print( "chips", Chip.Name )
      if Chip_Name.lower() == Chip.Name.lower():
         #print "chip found" ; print Chip_Name
         Chip.Python_Anchors = Python
         Chip.Set_Configuration( Configuration )
         return Chip
   #print "chip not found!!!"      
   return None
            
def mkt_Chip_File_Name( Chip_Name, Location = None ):
   for Chip in Chips:
      if Chip_Name.lower() == Chip.Name.lower():
         return Chip.Name.lower() + ".h"
   Errors.Raise( 
      Errors.Config_Error_Prefix + "unknown chip '%s'" % Chip_Name,
      Location )

def Section_Is( Line, Section_Names ):
   if not Line.startswith( "#section" ):
      return 0
   My_Line = Line.replace( "#section", "" ).strip()
   Section = ( My_Line + " x" ).split()[ 0 ].lower()
   if not Section in Global.Known_Sections:
      raise "unknown section '%s'" % Section
   return Section in Section_Names
   
class Toolkit:
   "using the GCC suite and other external tools"
   def __init__( 
      self, 
      Options
   ):
      self.Options  = Options
   
      # use the CodeSourcery GCC
      self.GCC       = "-gcc"
      self.GPP       = "-g++"
      self.DEBUG     = "-insight"
      self.OcdCmd    = r"C:\Program Files(x86)\ARMDevEnv\OCD Commander\Ocd_cmdl"
      self.OcdCmd    = r"C:\Program Files\Macraigor Systems\OCD Commander\Ocd_cmdl"
      self.OOCD      = "-oocd"
      self.COPY      = "-objcopy"
      self.NDSTOOL   = "ndstool"
      self.Temp      = Mkt_Temp
      
      C_Sections_Flags = ""
      L_Sections_Flags = ""
      if self.Options.Value( "sections" ):
         C_Sections_Flags = "-ffunction-sections -fdata-sections "
         L_Sections_Flags = "-Wl,--gc-sections "
      
      C_Optimization_Flags = ""   
      if self.Options.Value( "optimize" ):
         #C_Optimization_Flags = "-O%d " % self.Optimize
         C_Optimization_Flags = "-Os "
      # print( "opt %s [%s]" % ( Optimize, C_Optimization_Flags ))

      # -fstack-check seems to create stack-PROBING code, not very usefull
      # -fomit-frame-pointer is implied by -Os
      self.GCC_Flags = ""
      self.GCC_Flags += ( ""
          + "-g -pipe -Wall "
#          + "-Wno-multichar "
          + "-fno-builtin -c "
          + C_Sections_Flags
          + C_Optimization_Flags
      )
      self.GPP_Flags = self.GCC_Flags + ( ""
          + " -fno-threadsafe-statics " 
          + " -fno-use-cxa-get-exception-ptr "
#          + " -std=c++0x "
      )
      # print( self.Options.Value( "exceptions" ), self.Options )
      if not self.Options.Value( "rtti" ):
         self.GPP_Flags += " -fno-rtti "
      if not self.Options.Value( "exceptions" ):
         self.GPP_Flags += " -fno-exceptions "
         
      self.LD_Flags     = "-W-cref,--print-map,--gc-sections -nostartfiles "
      self.LD_Flags     += L_Sections_Flags
      
      self.ASM_Flags    = "-x assembler-with-cpp " + self.GCC_Flags
      self.Debug_Flags  = ""

      # by default: use GCC, not GPP
      self.Use_Cpp( 0 )
            
   def Cleanup( self ):   
      # print "cleanup [%s]" % self.Temp
      Directory_Files_Delete( self.Temp )

   def Tool( self, Name, Flags = "" ):
      "Full pathname of a tool, and add the flags"
      if Name == self.NDSTOOL:
         return '"' + self.GCC_Dir + "\\" + "ndstool" + '" ' + Flags
      if Name == self.OOCD:
         return '"' + self.GCC_Dir + "\\" + "openocd-ftd2xx" + '" ' + Flags
      if Name == self.DEBUG:
         return '"' + self.GCC_Dir + "\\" + \
            "arm-thumb-elf" + Name + '" ' + Flags
      return '"' + self.GCC_Dir + "\\" + self.GCC_Root + Name + '" ' + Flags
      
   def Temp_Dir( self, Name = "" ):
      return os.path.join( self.Temp, Name )

   def Temp_File( self, Name, Extension ):
      return self.Temp_Dir( 
         "_mkt_" + Extension + "_" + File_Base( Name ) + "." + Extension )

   # select either GCC (C/assembler) or GPP (C++)
   def Use_Cpp( self, Use_CPP ):
      self.I_Use_CPP = Use_CPP

   # this does return the exit code, os.system does not
   def System( self, Cmd, Echo = 1, Output = 1 ):
      if Echo and self.Options.Value( "echo" ):
         print( ">> " + Cmd )
      sys.stdout.flush()   
      Subprocess = subprocess.Popen( Cmd, stdout = Output, stderr = Output )
      Result = Subprocess.wait()
      sys.stdout.flush()   
      return Result

   # compile a single file
   def Compile( self, Name, Result ):
   
      # select the appropriate compiler
      Extension = File_Extension( Name ).lower()
      if Extension in [ "s", "asm" ]:
         Tool = self.Assembler
      elif Extension in [ "c" ]:
         Tool = self.C_Compiler
      elif Extension in [ "cpp", "c++" ]:
         Tool = self.Cpp_Compiler
         if Tool == None:
            Errors.Panic( "cpp file but cpp not selected" )  
            
      # compile          
      X = self.System( Tool + Name + " -o " + Result )
      if X:
         return X
         
      # if that worked OK: generate the assembler listing   
      if ( not self.Options.Value( "list" ) ) or ( Tool == self.Assembler ):
         return 0
      List_File = Replace_Extension( Result, 'lst' )
      Output = tempfile.TemporaryFile() 
      X = self.System( 
         Tool 
         + Name 
         + " -S -o " + List_File ,
         Echo = 0,
         Output = Output )
      Output.close()   
      if X:
         return X   
      # convert to DOS file format (just read and write)   
      Convert_To_DOS( List_File )
      return X

   # link the List of files to create the executable Name
   def Link( self, Name, List ):
      Map = Name + ".map"
      if self.Configuration.Matches( Mkt_Board, Mkt_NDSi ):
          X = self.System( 
            # r"C:\devkitPro\devkitARM\bin\arm-eabi-ld "
            self.Linker 
            #+ " -specs=ds_arm9.specs "
            + " -Wl,-Map,%s" % ( Map )
            + " -o " + Replace_Extension( Name, "elf" )
            + " " + List
            + " -mno-fpu "
            # + "-Lc:\devkitPro\PALib\lib -lpa9 "
            + "-Lc:\devkitPro\libnds\lib -lnds9 "
            # might one day need -lmm9 -lnds9 -lm 
         )
      else:
         X = self.System( self.Linker 
            + " -T" + self.Temp_Dir( Mkt_Link_Script )
            + " -Wl,-Map,%s" % ( Map )
            + " -o " + Replace_Extension( Name, "elf" )
            + " " + List
            + " -nodefaultlibs -lgcc"
         )
         # -lstdc++ lijkt geen goed idee
      Convert_To_DOS( self.Temp_Dir( Map ))
      return X
      
   def GCC_Find_At( self, Directory, Base ):
      self.GCC_Dir = Directory
      self.GCC_Root = Base
      return File_Exists( self.GCC_Dir + "\\" + self.GCC_Root + r"-cpp.exe" )
      
   def GCC_Find( self ):   
      GCC = self.Configuration.Get_Value( Mkt_GCC ).lower()
      if GCC == "armdevenv":
         if self.GCC_Find_At( r"C:\Program Files\ARMDevEnv\bin", "arm-thumb-elf" ): 
            return
         elif self.GCC_Find_At( r"C:\Program Files (x86)\ARMDevEnv\bin", "arm-thumb-elf" ): 
            return
         elif self.GCC_Find_At( r"C:\ARMDevEnv\bin", "arm-thumb-elf" ): 
            return
      elif GCC == "codescourcery":
         if self.GCC_Find_At( 
            r"C:\Program Files\CodeSourcery\Sourcery G++ Lite\bin", 
            "arm-none-eabi" ):
            return
         if self.GCC_Find_At( 
            r"C:\CodeSourcery\Sourcery G++ Lite\bin", 
            "arm-none-eabi" ):
            return           
      elif GCC == "devkitpro":
         if self.GCC_Find_At( 
            r"C:\devkitPro\devkitARM\bin", 
            "arm-eabi" ):
            return          
      elif GCC == "pic32gcc":
         if self.GCC_Find_At( 
            r"C:\Program Files\Microchip\MPLAB C32\bin", 
            "pic32" ):
            return          
      else:
         Errors.Panic( "invalid Mkt_GCC '%s'" % GCC )
      Errors.Raise( "no %s found" % GCC )
      
   def Set_Configuration( self, Configuration ):
      self.Configuration = Configuration
      self.GCC_Find()         
         
      self.GCC_Flags += self.Configuration.Chip.Chip_GCC_Flags
            
      if self.Configuration.Matches( Mkt_Board, Mkt_NDSi ):
         self.GPP_Flags += "-march=armv5te -mtune=arm946e-s -ffast-math -DARM9 "
         self.GPP_Flags += "-IC:/devkitPro/libnds/include "
         self.GPP_Flags += "-IC:/devkitPro/PAlib/include/nds "
         self.GPP_Flags += "-fbuiltin "
         
         self.LD_Flags  += "-specs=ds_arm9.specs "
         self.LD_Flags  = self.LD_Flags.replace( "-nostartfiles", "" )
         self.LD_Flags  = self.LD_Flags.replace( "-TCnostartfiles", "" )
         self.LD_Flags  += "-mno-fpu "
#         self.LD_Flags  += "-lnds9 "
         
      self.Assembler = self.Tool( self.GCC, self.ASM_Flags )
      if self.I_Use_CPP:
         self.C_Compiler    = self.Tool( self.GPP,   self.GCC_Flags )
         self.Cpp_Compiler  = self.Tool( self.GPP,   self.GPP_Flags )
         self.Linker        = self.Tool( self.GPP,   self.LD_Flags )
      else:
         self.C_Compiler    = self.Tool( self.GCC,   self.GCC_Flags )
         self.Cpp_Compiler  = None
         self.Linker        = self.Tool( self.GCC, self.LD_Flags )
      self.Debugger  = self.Tool( self.DEBUG, self.Debug_Flags )         
      
   def Error_List( self ):      
      T = Lines()
      for ( N, S ) in _Error_List:
         T.Add( "%3d %s" % ( N, S.strip() ))   
      return T
                           
   def Run( self, Name, Kill, Terminal ):
      Tool = self.Configuration.Must_Get( "run" ).Value.lower()
      try:
         if self.Configuration.Matches( Mkt_Board, Mkt_NDSi ):
            self.NDS_Run( Name )
         elif Tool == Mkt_Insight:
            self.Insight_Run( Name, Kill )
         elif Tool == Mkt_Lpc21isp:
            Error = self.Lpc21isp_Run( Name, Terminal )
            if Error:
               Errors.Raise( "lpc21isp returned error %s" % Error )
         elif Tool == Mkt_Ocd_Commander:
            self.Ocd_Commander_Run( Name )
         else:
            Config_Error
      except WindowsError:
         Errors.Raise( "the executable %s could not be found" % Tool )
         
   def NDS_Run( self, Name ):
      simulator = self.Configuration.Must_Get( Mkt_Emulator ).Value.lower()
      if( simulator == Mkt_DeSmuME ):
         return self.System(    
            r"C:\devkitPro\sim\DeSmuME\DeSmuME "
            + " " + Replace_Extension( Name, "nds" ).replace( "\\", r"/" )
         )
      if( simulator == Mkt_Ideas ):
         return self.System(    
            r"C:\devkitPro\PAlib\emulators\ideas\ideas "
            + " " + Replace_Extension( Name, "nds" ).replace( "\\", r"/" )
         )
      if( simulator == Mkt_NoGBA ):
         return self.System(    
            r"C:\devkitPro\PAlib\emulators\no$gba\NO$GBA "
            + " " + Replace_Extension( Name, "nds" ).replace( "\\", r"/" )
         )
      if( simulator == Mkt_dualis ):
         return self.System(    
            r"C:\devkitPro\sim\dualis\dualis "
            + " " + Replace_Extension( Name, "nds" ).replace( "\\", r"/" )
         )
      Config_Error
           
   def Insight_Cfg_Simulator( self, Elf ):
      Lines_From_Text( """         
         [session]       
         DIR/target=sim
         DIR/run_cont=1
         DIR/executable=%s
         DIR/all-keys=run_cont \
         run_run breakpoints executable dirs target_cmd pwd \
         port bg run_attach run_load args target hostname
         DIR/bg=0
         DIR/port=8888
         DIR/dirs=$cdir;$cwd
         DIR/run_attach=1
         DIR/run_load=1
         DIR/breakpoints={{break exit} 1 {} {}} {{break main} 1 {} {}}
         DIR/target_cmd=sim
         DIR/pwd=%s
         DIR/run_run=1
      """.replace( "DIR", self.Temp_Dir( Elf )\
         .replace( "\\", "/" ).replace( "c:", "C:")) % (
         Elf, self.Temp_Dir().replace("c:","C:")
      )).Write( self.Temp_Dir( "-gdbtk.ini" ))   
      
      Lines_From_Text( """         
         [session]
           DIR/dirs=$cdir;$cwd
           DIR/run_attach=1
           DIR/run_load=1
           DIR/breakpoints={{break main} 1 {} {}}
           DIR/target_cmd=sim 
           DIR/pwd=c:\_mkt_temp
           DIR/run_run=1
           DIR/target=sim
           DIR/run_cont=0
           DIR/executable=C:/_mkt_temp/result.elf
           DIR/all-keys=run_cont run_run breakpoints executable dirs \
         target_cmd pwd port bg run_attach run_load args target hostname
           DIR/bg=0
           DIR/port=1000  
      """.replace( "DIR", self.Temp_Dir( Elf )) 
      ).Write( self.Temp_Dir( "gdbtk.ini" )) 
         
   def Insight_Cfg_Wiggler( self, Elf ):
      Lines_From_Text( """         
         # GDBtk Init file
         # GDBtkInitVersion: 1
         [session]
         DIR/hostname=127.0.0.1         
         DIR/target=remotetcp
         DIR/run_cont=1
         DIR/executable=%s
         DIR/all-keys=run_cont \
         run_run breakpoints executable dirs target_cmd pwd \
         port bg run_attach run_load args target hostname
         DIR/bg=0
         DIR/port=8888
         DIR/dirs=$cdir;$cwd
         DIR/run_attach=1
         DIR/run_load=1
         DIR/breakpoints={{break exit} 1 {} {}} {{break main} 1 {} {}}
         DIR/target_cmd=remote 127.0.0.1:8888
         DIR/pwd=%s
         DIR/run_run=0
      """.replace( "DIR", self.Temp_Dir( Elf ).\
         replace( "\\", "/" ).replace( "c:", "C:")) % (
         Elf, self.Temp_Dir().replace("c:","C:")
      )).Write( self.Temp_Dir( "gdbtk.ini" ))
      # Lines_From_Text( "" ).Write( self.Temp_Dir( "gdbtk.ini" ))   
      
   def OOCD_Cfg( self, File_Name, PID, VID, Name, Layout ):
      Lines_From_Text( """         
         #daemon configuration
         telnet_port 4444
         gdb_port 8888
         
         # tell gdb our flash memory map
         # and enable flash programming
         #gdb_memory_map enable
         gdb_flash_program enable
         
         #interface
         interface ft2232
         ft2232_vid_pid 0x%04X 0x%04X
         ft2232_device_desc "%s"
         ft2232_layout "%s"
         
         #arm7_9 sw_bkpts enable
         
         #ft2232_layout oocdlink
         #ft2232_vid_pid 0x0403 0xbaf8
         ft2232_vid_pid 0x1457 0x5118
         jtag_speed 05
         
         #use combined on interfaces or targets that 
         # can't set TRST/SRST separately
         #reset_config srst
         #reset_config trst_and_srst srst_pulls_trst
         reset_config trst_and_srst
         #reset_config trst 
         #reset_config srst_only
         
         
         #LPCs need reset pulled while RTCK is low. 
         # 0 to activate JTAG, power-on reset is not enough
         jtag_reset 1 1
         jtag_reset 0 0
         
         #jtag scan chain
         #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
         jtag_device 4 0x1 0xf 0xe
         
         #target configuration
         daemon_startup reset
         
         #target <type> <startup mode>
         #target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
         target arm7tdmi little run_and_halt 0 
         
         #target arm7tdmi little run_and_halt 0 arm7tdmi-s_r4
         run_and_halt_time 0 30
         
         working_area 0 0x40000000 0x4000 nobackup
         
         #flash bank lpc2000 <base> <size> 0 0 <target#> <variant>
         flash bank lpc2000 0x0 0x7d000 0 0 0 lpc2000_v2 14765 calc_checksum
         
         # For more information about the configuration files, 
         # take a look at:
         # http://openfacts.berlios.de/index-en.phtml?title=Open+On-Chip+Debugger
         # new version of OPENocd accept command in OCD loader
         arm7_9 force_hw_bkpts enable
      """ % ( VID, PID, Name, Layout )).Write( File_Name )
         
   def Insight_Run( self, Name, Kill ):
      Connection = self.Configuration.Must_Get( Mkt_Link ).Value
           
      Elf = Replace_Extension( Name, "elf" )\
         .replace( "c:", "C:" ).replace( "\\", "/" )
      
      if Connection == Mkt_Simulator:
         self.Insight_Cfg_Simulator( Elf )
         
      elif Connection == Mkt_ARM_USB_OCD:
         self.Insight_Cfg_Wiggler( Elf )
         Cfg = self.Temp_Dir( Mkt_OOCD_Cfg )
         self.OOCD_Cfg( 
            Cfg, 
            0x15BA, 
            0x0003, 
            "Olimex OpenOCD JTAG A", 
            "olimex-jtag",
         )
         self.System( 'cmd /c start "OpenOCD" %s -f %s' % 
            ( self.Tool( self.OOCD ), Cfg ))

      elif Connection == Mkt_FTDI2232:
         self.Insight_Cfg_Wiggler( Elf )
         Cfg = self.Temp_Dir( Mkt_OOCD_Cfg )
         self.OOCD_Cfg( 
            Cfg, 
            0x5118, 
            0x1457, 
            "Debug Board for lpc21xx A",
            "jtagkey", 
         )
         self.System( 'cmd /c start "OpenOCD" %s -f %s' % 
            ( self.Tool( self.OOCD ), Cfg ))
         
      elif Connection == Mkt_Wiggler:
         self.Insight_Cfg_Wiggler( Elf )
         OcdLibRemote = "OCDLibRemote"
         self.System( 
            'cmd /c start "%s" OcdLibRemote --cpu ARM7 --device WIGGLER' %
            OcdLibRemote )
      else:
         Errors.Panic( "com=%s" % Connection )
         
      Lines_From_Text( """
         set breakpoint pending off
         set complaints 0
      """ ).Write( self.Temp_Dir( Mkt_Insight_Cmd )) 
           
      Result = self.System( 
         ( 'cmd /C "CD /D "%s" &&' % self.Temp_Dir())
         + self.Debugger
         + ( " --command=%s " 
            % self.Temp_Dir( Mkt_Insight_Cmd ).replace( "\\", r"/" ) )
         + " " + Replace_Extension( Name, "elf" ).replace( "\\", r"/" )
         + '"' )   
         
      if Kill:
         if (
            not Try_Kill_Process( "openocd-ftd2xx" )
            or not Try_Kill_Process( "OCDLibRemote" )   
         ):
            print( "warning: could not kill the background process" )
         
      return Result            
      
   def Lpc21isp_Run( self, Name, Terminal ):
      Format = "-bin"
      if File_Extension( Name ).lower() == "hex":
         Format = "-hex"
      Term = ""
      if Terminal:
         Term = "-term"   
      F = File_Find_Executable( "lpc21isp.exe" )
      if F == None:
         Errors.Raise( "lpc21isp executable could not be found in path" )
      return self.System(    
         F 
         + " " + Format
         + " " + "-control"
         + " " + Term
         + " " + Name.replace( "\\", r"/" )
         + " " + self.Configuration.Must_Get( Mkt_Port ).Value
         + " " + str( int( self.Configuration.Must_Get( Mkt_Baudrate ).Value ))
         + " " + str( int( self.Configuration.Numeric_Value( Mkt_Xtal ) / kHz ))
      )

   def Ocd_Commander_Run( self, Name ):
      print( "type 'run' in OCD Commander to re-start the application." )
      print( "Please close the OCD Commander when you are finished." )
      MacroFile = self.Temp_Dir( "run.MAC" )
      Elf = self.Temp_Dir( Replace_Extension( Name, "elf" ))
      Macro = Lines_From_Text( """
         reset
         download %s
         go
      """ % Elf )
      Macro.Write( MacroFile )
      return self.System(    
         '"' + self.OcdCmd + '"'
         + " " + MacroFile
      )

   def Elf_To_Bin( self, Name ):
      return self.System( 
         self.Tool( self.COPY )
         + " -O binary --set-start 0 "
         + Replace_Extension( Name, "elf" ).replace( "\\", r"/" ) + " "
         + Replace_Extension( Name, "bin" ).replace( "\\", r"/" )
      )
      
   def Elf_To_Hex( self, Name ):      
      return self.System( 
         self.Tool( self.COPY )
         + " -O ihex "
         + Replace_Extension( Name, "elf" ).replace( "\\", r"/" ) + " "
         + Replace_Extension( Name, "hex" ).replace( "\\", r"/" )
      )

   def Elf_To_NDS( self, Name ):      
      return self.System( 
         # r"set NDSTOOL=C:\devkitPro;" +
         self.Tool( self.NDSTOOL )
         + " -c " + Replace_Extension( Name, "nds" ).replace( "\\", r"/" ) + " "
         + " -9 "
         + Replace_Extension( Name, "elf" ).replace( "\\", r"/" )
      )

    
#############################################################################
#
# special handling of source lines
#
#############################################################################
   
def Lines_From_Image( Image, Object_Name, Invert = 0 ):
   Result = Lines()
   Result.Add( "const unsigned char %s_pixels[] = { " % Object_Name )
   x_size, y_size = Image.size
   comma = " "
   for y in range( y_size ):
      m = 0x80
      d = 0
      S = "/* y = %03d */ " % y
      for x in range( x_size ):
         pixel = Image.getpixel((x,y))
         try:
            red, green, blue = pixel
            v = (( 255 - red ) + ( 255 - green ) + ( 255 - blue ))
         except:
            v = ( 255 - pixel )            
         if Invert: 
            if ( v > 0 ):
               d = d + m         
         else:
            if ( v <= 0 ):
               d = d + m
         if 0: print( x, y, pixel, v, m, d )
         m = m / 2
         if( m == 0 ) | ( x == x_size-1):
            # print( "====> %02X" % d )
            S += ( "%s0x%02X" % ( comma, d ))
            m = 0x80
            d = 0
            comma = ","
         if len( S ) > 70:
            Result.Add( "   %s" % S  )
            S = ""
      Result.Add( "   /* */ %s" % S )     
   Result.Add( "   %s" % S )     
   Result.Add( "};" )
   Result.Add( "const mkt_picture %s = { " % Object_Name )
   Result.Add( "   /* x_size  */ %d, " % x_size )
   Result.Add( "   /* y_size  */ %d, " % y_size )
   Result.Add( "   /* stride  */ %d, " % (( x_size + 7 ) / 8 ))
   Result.Add( "   /* format  */ %d, " % 0 )
   Result.Add( "   /* pixels  */ %s_pixels "  % Object_Name )
   Result.Add( "};" )
   return Result         
   
def Source_Line_Font( Project, Object_Name, File_Name, Size ):
   try:
      import PIL
      import ImageFont # , ImageDraw
   except:
      Errors.Raise( "Error: the python PIL module is not installed." )  
   try:
      Font = ImageFont.truetype( File_Name, int( Size ))
   except:
      Errors.Raise( "Error: ttf file %s could not be opened" % File_Name )
   Result_File_Name = Project.Toolkit.Temp_File( 
      File_Name.replace( ".", "_" ), "inc" )      
   Chars = ""   
   List = "0"
   Max = 0
   Min = 10000
   Last = 0
   Mode = "1"
   for i in range( ord( ' ' ), ord( '~' ) + 1 ):
#   for i in range( ord( 'a' ), ord( 'z' ) + 1 ):
      Chars = Chars + chr( i ) 
      ( Total, Height ) = Font.getmask( Chars, mode = Mode ).size
      Len = Total - Last
      Last = Total
      if Len < Min : Min = Len
      if Len > Max : Max = Len
      List = List + ( ",%d" % Total )
   Image = Font.getmask( Chars, mode = Mode )
   if 0: print( Min, Max, List )
   #if Min != Max:
   #   Errors.Raise( "font %s is not fixed-size" % File_Name )
   #Image.show()
   #Image.save( Object_Name + '.jpg', "JPEG" )
   Result = Lines_From_Image( Image, Object_Name + "_picture" )
   Width = 0
   if Max == Min:
      Width = Max
      Start_Address = "0"
   else:
      Result.Add( "const short int %s[] = {" % ( Object_Name + "_Start" ))
      Result.Add( "   %s" % List );
      Result.Add( "};" )
      Start_Address = Object_Name + "_Start"
   Result.Add( "const mkt_font %s = { " % Object_Name )
   Result.Add( "   /* x_size   */ %d, " % Width )
   Result.Add( "   /* y_size   */ %d, " % Height )
   Result.Add( "   /* list     */ %s, " % 0 )
   Result.Add( "   /* start    */ %s, " % Start_Address )
   Result.Add( "   /* picture  */ &%s "  % ( Object_Name + "_picture" ))
   Result.Add( "};" )
   Result.Write( Result_File_Name )
   return '#include "%s"' % Result_File_Name  

def Source_Line_Image( Project, Object_Name, File_Name ):
   try:
      from PIL import Image
   except:
      Errors.Raise( "Error: the python PIL module is not installed." )  
   Result_File_Name = Project.Toolkit.Temp_File( 
      File_Name.replace( ".", "_" ), "inc" )
   try:   
      Image = Image.open( File_Name )
   except:
      Errors.Raise( "Error: image file %s could not be opened" % File_Name )      
   Result = Lines_From_Image( Image, Object_Name, Invert = 1 )
   Result.Write( Result_File_Name )
   return '#include "%s"' % Result_File_Name

def Source_Line_Sound( Project, Object_Name, File_Name, Max = 1000000 ):
   import wave
   Result_File_Name = Project.Toolkit.Temp_File( 
      File_Name.replace( ".", "_" ), "inc" )
   try:   
      Wav = wave.open( File_Name, "rb" )
   except:
      Errors.Raise( "Error: sound file %s could not be opened" % File_Name )
   # print Wav.getparams()   
   (nchannels, sampwidth, framerate, nframes, d1, d2) = Wav.getparams()
   if nchannels != 1:
      Errors.Raise( "Error: sound file %s has %d channels (must be 1 )" 
         % ( File_Name, nchannels ))
   if sampwidth != 1:
      Errors.Raise( "Error: sound file %s has sampwidth %d (must be 1 )" 
         % ( File_Name, sampwidth ))
   Wav.rewind()
   Result = Lines()
   Result.Add( "const unsigned char %s_frames[] = { " % Object_Name )
   Line = "   "
   n = 0
   if nframes > Max:
     nframes = Max
   for c in Wav.readframes( nframes ):
      if n % sampwidth == 0:
         Line += "0x%02X," % ord( c )
         if len( Line ) > 70:
            Result.Add( Line )
            Line = "   "
      n += 1
   Result.Add( Line + "0};" )
   Result.Add( "const mkt_sound %s = { " % Object_Name )
   Result.Add( "   /* rate     */ %d, " % framerate )
   Result.Add( "   /* nframes  */ %d, " % nframes )
   Result.Add( "   /* frames   */ %s_frames " % Object_Name )
   Result.Add( "};" )         
   Result.Write( Result_File_Name )
   return '#include "%s"' % Result_File_Name

def Source_Line_Filter( Project, Line ):
   if Line.strip().startswith( "mkt_picture" ):
      return eval( Line
         .replace( "mkt_picture", "Source_Line_Image" )
         .replace( "(", "( Project, " ).replace( ");", ")" ))
   elif Line.strip().startswith( "mkt_font" ):
      return eval( Line
         .replace( "mkt_font", "Source_Line_Font" )
         .replace( "(", "( Project, " ).replace( ");", ")" ))
   elif Line.strip().startswith( "mkt_sound" ):
      return eval( Line
         .replace( "mkt_sound", "Source_Line_Sound" )
         .replace( "(", "( Project, " ).replace( ");", ")" ))
   else:
      return Line
    
class Project:

   def __init__( self, Options ):
      self.Options = Options
      self.File_Names = []
      self.Toolkit = Toolkit( self.Options )

   def Extract_Config( self, Files, Section_Names, Extensions = [] ):
      Result = Lines()
      for File in Files:         
         Use_Block = File_Extension( File.Name ).upper() in Extensions
         Use_Last_Line = 0
         for Line in File.Lines:
            Use_This_Line = Line.Text.startswith( "#configure" )
            if Line.Text.startswith( "#section" ):
               Use_Block = 0
            if Use_Block or Use_This_Line:
               if not Use_Last_Line:
                  Result.Add( Line.Anchor())
               Result.Add( 
                  Line.Text.replace( "#configure", "#define" ),
                  Line.Location )
               Use_Last_Line = 1
            else:
               Use_Last_Line = 0            
            if Section_Is( Line.Text, Section_Names ):
               Use_Block = 1
      return Result

   def Extract_Source( self, File, Section_Names ):
      Result = Lines()
      Result.Add( Include_Local( Mkt_Header_H ) + "\n" )
      Result.Add( '#line %d "%s"\n' % ( 1, File.Name.replace( "\\", "\\\\" ) ))
      N = 0
      for Line in File.Lines:
         N = N + 1
         if Line.Text.startswith( "#section" ):
            Errors.Raise( 
               "#section not allowed in a non-mkt source file", 
               Line.Location )
         if Line.Text.startswith( "#configure" ):
            Result.Add( "" )
         elif Line.Text.startswith( "#require" ):
            for Name in Line.Text.split()[1:]:
               if File_Extension( Name ) in [ "h", "hpp" ]:
                  Result.Add ( '#line %d\n' % N )
                  Result.Add( '#include "%s"\n' % Name )
         else:
            Result.Add( Line.Text )
      return Result

   def Comment_Configs( self, Line ):
      if Line.startswith( "#configure" ):
         return "//" + Line 
      elif Line.startswith( "#require" ):
         return "//" + Line 
      else:
         return Line

   def Required_Files( self, Lines ): 
      List = []
      for Line in Lines:
         if Line.Text.startswith( "#require" ):
            for File in Line.Text.split()[1:]:
               List.append( File )
      # print( "list=", List )   
      return List

   def Make_Temporary( 
      self, 
      File, 
      Section_Names = [], 
      Extension = "", 
      Header = 0 
   ):
      Temp = self.Extract_Source( File, Section_Names )
      FileName = os.path.basename( File.Name )
      # FileName = File.Name
      if Header:   
         Temp.Set_File_Name( self.Toolkit.Temp_Dir( FileName ))
         # print( self.Toolkit.Temp_Dir( File.Name ))
      else:
         Temp.Set_File_Name( self.Toolkit.Temp_File( FileName, Extension ))
      self.Temporaries.append( Temp )   
      return Temp.Number_Of_Lines()
       
   def Build( self ):
      self.Silent = self.Options.Value( "silent" )
      self.Build = self.Options.Value( "build" )
      self.File_Names = self.Options.Files
   
      if self.Options.Value( "docs" ):
         Chip = mkt_Chip( 
            Chips[ 0 ].Name,
            Configuration(),
            self.Options.Value( "python" )
         )
         Text = Chip.Get_Documentation()
         if 0: # for debugging 
            Text.Write( "raw.txt" )
         Doc = Documentation( Text ) 
         # this is the active list!      
         List = [
            "introduction",
            "installation",
            "use",
#            "start-with-devcpp",
#            "ea-configuration",
#            "tools",
#            "ea-file-format",
#            "ea-chips",
#            "ea-boards",
#            "ea-startup",
#            "linker-script",
#            "exception-vectors",
#            "run-from-RAM",
            "busy-waiting",
#            "fatal-error-handling",
            "memory-allocation",
            "stacks",
            "coroutines",
#            "interrupts",
            "basic-io",
            "leds",
            "char-lcd",
#            "graphic-lcd",
            "uart",
#            "char-format",
            "streamio",
#            "memory-sections",
#            "boards",
#             "asm-intro",
         ]
         if 0 : List = [ # for debugging
            "memory-sections",
         ]
         Doc.MakeHTML( "manual", "MicroKit", List )       
         return
   
      # cleanup temporary directory?
      if self.Options.Value( "cleanup" ):   
         self.Toolkit.Cleanup()
      
      # read all files
      self.Files = []
      Images = 0
      for File_Name in self.File_Names:
         if self.Options.Value( "ignorepath" ):
            File_Name = os.path.basename( File_Name )
         if self.Options.Value( "clever" ):
            File_Name = Clever_File_Find( 
               File_Name, 
               [ ".c", ".h", ".s", ".cpp", ".hex", ".bin" ] )
         if File_Extension( File_Name  ).lower() in [ "hex", "bin" ]:
            Images += 1
            Image_File = File_Name
         else:
            This_File = Lines( File_Name, Filter = Unique )
            self.Files.append( This_File )
            for Required_File in self.Required_Files( This_File.Lines ):
               if not Required_File in self.File_Names:
                  self.File_Names.append( Required_File )
                  if not File_Exists( Required_File ):
                     Errors.Raise( 
                        "can not open file %s as required by %s" %
                        ( Required_File, File_Name ))

      # print( "file names=", self.File_Names )
            
      # check for image file arguments      
      if Images > 1:
         Errors.Raise(
            "more than one image file specified; \n"
            + "please specify only one" )        
      if Images == 1:
         if len( self.Files ) > 1:
            Errors.Raise( 
               "both an image file and source file(s) specified; \n"
               + "please specify only the image file" )   
         Build = 0    
         Defines.append( "memory=rom" )                                 
         
      # create configuration  
      if not self.Silent:
         print( "gather configuration" )
      self.Config = self.Extract_Config( 
         self.Files, [ "configure", "configuration" ], [ "mtk" ] )
      
      # create temporaries (in-memory)
      self.Temporaries = []
      Count_Cpp = 0
      if self.Build:
         if not self.Silent:
            print( "create temporary files" )
         for File in self.Files:
         
            if 0 : File.Write( 
               self.Toolkit.Temp_Dir( File.Name ),
               Filter = self.Comment_Configs
            )

            if File.Extension in [ "mkt", "c" ]:
               self.Make_Temporary( File, [ "c" ], "c" )      
   
            elif File.Extension in [ "mkt", "c++", "cpp" ]:
               Count_Cpp = Count_Cpp + \
                  self.Make_Temporary( File, [ "c++", "cpp" ], "cpp" )            
   
            elif File.Extension in [ "mkt", "asm", "s" ]:
               self.Make_Temporary( File,  [ "asm", "assembler" ], "s" )     
   
            elif File.Extension in [ "h", "hpp", "inc" ]:
               self.Make_Temporary( File,  Header = 1 )     
   
            else:
               Errors.Raise( "source file '%s' has unknown file type '%s'" 
                  % ( File.Name, File.Extension )) 
       
      # (re!) create toolkit
      # print( "Cpp=%d\n" % Count_Cpp )
      self.Toolkit = Toolkit( Options = self.Options )
      self.Toolkit.Use_Cpp( Count_Cpp )
      
      # parse configuration
      self.Configuration = Configuration()
      for Line in self.Config.Lines:
         self.Configuration.Parse( Line )
      self.Configuration.Add_Defines( self.Options.Defines )
      if self.Options.Value( "config" ):
         print( str( self.Configuration ))
      if self.Build:   
         self.Config.Write( self.Toolkit.Temp_Dir( Mkt_Config_TXT ))

      # create chip include file
      self.Configuration.Activate_Defaults()
      if self.Configuration.Chip_Name() == "":
         Errors.Raise( "no chip specified" )
      Chip = mkt_Chip( 
         self.Configuration.Chip_Name(), 
         self.Configuration,
         self.Options.Value( "python" ) 
      )
      if Chip == None:
         Errors.Raise( "invalid chip name '%s'" % self.Configuration.Chip_Name() )
      self.Configuration.Check()
      if self.Options.Value( "config" ):
         print( str( self.Configuration ))
      if not self.Silent:
         print( "building library for %s" % self.Configuration.Chip_Name())
      self.Configuration.Chip = Chip   
      self.Toolkit.Set_Configuration( self.Configuration )
      
      # create user include file
      Header = Lines()
      if not self.Configuration.Matches( Mkt_Board, Mkt_NDSi ):
         Header.Add( Global.Notice, Filter = Comment )
         Header.Add( "#ifndef _mkt__header\n" )
         Header.Add( "#define _mkt__header\n" )
         Header.Add( Include_Local( Mkt_Config_H ))
         Header.Add( Include_Local( mkt_Chip_File_Name( 
            self.Configuration.Chip_Name())))
         Header.Add( Include_Local( Mkt_Lib_H ))
         Header.Add( "#endif\n" )
      if self.Build:
         Header.Write( self.Toolkit.Temp_Dir( Mkt_Header_H ))

      # dit is lelijk, file name moet hier beslist worden!
      if self.Build:
         Chip.Make_Chip_Header( Directory = self.Toolkit.Temp_Dir() )
      
      if not self.Configuration.Matches( Mkt_Board, Mkt_NDSi ):
         # create configuration include file
         if self.Build:
            self.Configuration.Header().Write( 
               self.Toolkit.Temp_Dir( Mkt_Config_H ))
      
         # create library header
         if self.Build:
            Chip.Get_Header( 
               self.Toolkit.Temp_Dir( Mkt_Lib_H )).Write()
      
         # create library sources
         self.Temporaries.append( 
            Chip.Get_Assembler( self.Toolkit.Temp_Dir( Mkt_Lib_ASM )))
         self.Temporaries.append( 
            Chip.Get_C( self.Toolkit.Temp_Dir( Mkt_Lib_C )))
         if Count_Cpp > 0:
            self.Temporaries.append( 
               Chip.Get_CPP( self.Toolkit.Temp_Dir( Mkt_Lib_CPP )))

      # compile
      Objects = " "
      if self.Build:
         for Temp in self.Temporaries:
            Temp.Write()
         for Temp in self.Temporaries:
            if not File_Extension( Temp.File_Name ) in [ "h", "hpp" ]:
               File_Name = Temp.File_Name
               Object_Name = Replace_Extension( File_Name, "o" )
               if not self.Silent:
                  print( "compile %s" % File_Name )
               if self.Toolkit.Compile( File_Name, Object_Name ):
                  Errors.Raise( "compilation failed" )
               Objects += Object_Name + " "
               
      # link 
      if self.Build:
         if not self.Silent:
            print( "link" )
         Chip.Get_Linker_Script( 
            self.Toolkit.Temp_Dir( Mkt_Link_Script )).Write()
         if self.Toolkit.Link( 
            self.Toolkit.Temp_Dir( "result" ), 
            Objects 
         ):
            Errors.Raise( "linking failed" )
      if Images == 0:
         Map = Map_Info( self.Toolkit.Temp_Dir( "result.map" ))
         Map.Regions_Lines().Write( 
            self.Toolkit.Temp_Dir( "result_regions.txt" ))
         Map.Section_Lines().Write( 
            self.Toolkit.Temp_Dir( "result_sections.txt" ))
         if not self.Silent:
            print( str( Map.Regions_Lines().Plain_Text()))
            if self.Options.Value( "size" ):
               print( str( Map.Section_Lines().Plain_Text()))

      Map_File_Content = Lines( 
         File_Name = self.Toolkit.Temp_Dir( "result.map" ))
      fp_re = re.compile( Global.floating_point_functions_list )
      # print( Map_File_Content.__str__() )
      if fp_re.search( Map_File_Content.__str__() ):
         Errors.Raise( "*** floating point functions are used" )
               
      # create list of error codes
      E = self.Toolkit.Error_List()
      E.Write( self.Toolkit.Temp_Dir( "error_codes.txt" ))
      if self.Options.Value( "errors" ):
         print( "application abort codes" )
         E.Print( Prefix = "   " )
         
      # convert
      if self.Build:
         # this takes a long time!
         # self.Toolkit.Elf_To_Bin( self.Toolkit.Temp_Dir( "result" ))
         
         if self.Configuration.Matches( Mkt_Board, Mkt_NDSi ):
            self.Toolkit.Elf_To_NDS( self.Toolkit.Temp_Dir( "result" ))
         else:
            self.Toolkit.Elf_To_Hex( self.Toolkit.Temp_Dir( "result" ))
         
      # get the image file?   
      # Image = self.Toolkit.Temp_Dir( "result.bin" )
      Image = self.Toolkit.Temp_Dir( "result.hex" )
      if ( Images == 1 ): 
         Image = self.Toolkit.Temp_Dir( 
               "result." + 
               ( File_Extension( Image_File ).lower())
            )
         shutil.copy( os.path.abspath( Image_File ), Image )         
         
      # run
      if self.Options.Value( "run" ):
        if not self.Silent:
            print( "run" )  
        self.Toolkit.Run( 
           Image, 
           Kill = self.Options.Value( "kill" ), 
           Terminal = self.Options.Value( "term" )
        )

def pixel_to_bit(pixel,threshold=128):
    """Convert the pixel value to a bit."""
    if pixel > threshold:
        return 1
    else:
        return 0

#
#   Netbeans_Read added by Mike Schaap
#

def Netbeans_Read():
    "Read file list from Netbeans configuration.xml file."
    List = []
    HeaderFiles = []
    SourceFiles = []
    from xml.dom import minidom
    doc = minidom.parse('nbproject/configurations.xml')
    for node in doc.getElementsByTagName('logicalFolder'):
        if node.getAttribute('name') == 'HeaderFiles':
            for child in node.getElementsByTagName('itemPath') :
                HeaderFiles.append(str(child.childNodes[0].nodeValue))
        elif node.getAttribute('name') == 'SourceFiles' :
            for child in node.getElementsByTagName('itemPath') :
                SourceFiles.append(str(child.childNodes[0].nodeValue))
  
    ProjectFiles = []
    for line in HeaderFiles :
        ProjectFiles.append(str(line))
        
    for line in SourceFiles :
        ProjectFiles.append(str(line))
    return ProjectFiles

      
def PSPad_Read():
   "read file list from a PSPad project.ppr file"
   
   List =  []
   Use = 0
   for Line in Lines( "Project.ppr" ).Lines:
      Line = Line.Text.strip()
      if Line.startswith( "+includes" ):
         Use = 1
      elif Line.startswith( "-includes" ):
         Use = 1
      elif Line.startswith( "+compile" ):
         Use = 1
      elif Line.startswith( "-compile" ):
         Use = 1
      elif Line.startswith( "+others" ):
         Use = 0
      elif Line.startswith( "-others" ):
         Use = 0
      elif Line.startswith( "[" ):
         Use = 0
      elif Use:
         List.append( Line )
   print( "pspad file list " + str( List ))         
   return List
   
def PSPad_Glue():   
   "create PSPad glue files"
   Path = ""
   for Version in [ "31", "30", "27", "26", "25" ]:
      Path = Path + "PATH=%PATH%" + \
         ( ";C:\Python%s" % Version ) + \
         ( ";C:\Program Files\Python%s" % Version ) + \
         "\n"
   Lines_From_Text( """
      @echo off
      rem
      rem This scipt is called from PsPAD.
      rem The aim is to call "python mkt.py" 
      rem with appropriate arguments
      rem
      echo mktrun from mkt MKT-VERSION
      rem
      
      rem Try to locate the Python executable, it might not
      rem be in the current PATH 
      PYTHON-PATH
      
      rem if called with no arguments: build the application
      set CARGS=%1 %2 %3 %4 %5 %6 %7 %8 %9
      if x%1==x (
         set CARGS=-build
      )   
      
      rem default arguments
      set DARGS= -pspad -optimize -sections -noclever -errors
      
      set ARGS=%DARGS% %CARGS%
      
      if "%1" == "-echo" (
         echo %2 %3 %4 %5 %6 %7 %8 %9
         set ARGS=-version -pause
      )
      
      rem check for the mkt.py file in this directory and 
      rem a few steps higher up in the tree
      if exist .\mkt.py (
         python .\mkt.py %ARGS%
         goto done
      ) 
      if exist ..\mkt.py (
         python ..\mkt.py %ARGS%
         goto done
      )   
      if exist ..\..\mkt.py (
         python ..\..\mkt.py %ARGS%
         goto done
      )   
      if exist ..\..\..\mkt.py (
         python ..\..\..\mkt.py %ARGS%
         goto done
      )   
      
      rem sorry, no mkt.py file found :(
      echo "error: no mkt.py file found"
      
      :done
   """
      .replace( "PYTHON-PATH", Path )
      .replace( "MKT-VERSION", Global.Version )
   ).Write( "mktrun.bat" )
   
   Project1 = Lines_From_Text( """
      [Config]
      Compilator.FileName=mktrun.bat
      Compilator.DefaultDir=
      Compilator.SaveAll=1
      Compilator.Capture=1
      Compilator.ParsLog=%F:%L:*
      Compilator.HideOutput=1
      Compilator.LogType=0
      Prog1=Build,cmd /C "mktrun.bat -build -errors -pause"�
      Prog2=Build and run,cmd /C "mktrun.bat -term -errors -pause "�
      Prog3=Run only,cmd /C "mktrun.bat -nocleanup -run -term -errorpause"�
      Prog4=show mkt versions,cmd /C "mktrun.bat -echo Project.ppr from MKT-VERSION"�
   """.replace( "MKT-VERSION", Global.Version ))
   Project2 = Lines_From_Text( """
      DefaultCPIndex=0
      LogtoEnd=1
      DontOpen=0
      AbsolutePath=0
      FileFormat=0
      ProjectFilesOnly=0
      [Project tree]
      Project
      	+Files
      		-includes
      		-compile
      		-others
      			mktrun.bat
      [Open project files]
      [Selected Project Files]
      Main=
   """ )
   Project_File_Name = "Project.ppr"
   if Files.File_Exists( Project_File_Name ):
      Project2 = Lines( File_Name = Project_File_Name )
      while (
         ( len( Project2.Lines ) > 0 )
         and ( not Project2.Lines[ 0 ].Text.startswith( "Default" ))
      ):
         Project2.Lines.pop( 0 )      
   ( Project1 + Project2 ).Write( Project_File_Name )

   
def Print_Help():
   "print help text" 
   print( """
   usage:
      mkt { option | define | source-file }
      
   options:
      -build          : just build, do not run
      -[no]catch      : catch and handle Python errors (yes)
      -[no]cleanup    : first empty the temporary directory (yes)
      -[no]clever     : try file suffixes .c,.s,.h,.cpp (yes)
      -[no]config     : show configuration (no)
      -docs           : generate the documentation
      -[no]echo       : echo tool commands (no)
      -[no]errorpause : pause at the end if an eror occurred (no)
      -[no]errors     : show list of application error codes (no)
      -[no]exceptions : include support for exceptions (no)
      -go             : build and run (default)
      -help           : print this text
      -[no]kill       : kill deamons after debugging (yes)
      -[no]list       : make asm listings for C/C++ files (yes)
      -[no]optimize   : optimize (no)
      -[no]pause      : pause at the end
      -pspad          : read source file names from PsPad project.ppr file
      -pspadglue      : write glue files for PsPad
      -[no]python     : make library errors point to the python source
      -ram            : run from RAM (same as memory=ram)
      -rom            : run from ROM (same as memory=rom)
      -run            : just run, do not build
      -[no]rtti       : include support for rtti (no)
      -[no]sections   : use separate function sections (yes)
      -[no]ignorepath : allow but ignore paths in source file names (no)
      -[no]size       : show size details (no)
      -silent         : neither print steps, nor echo tool commands
      -[no]term       : start terminal (no)
      -version        : show mkt version
   For binary choices the default is shown in parenthesis.
   
   define syntax:
      item=value
      
   All other arguments (not starting with a -, do not contain a =)
   are assumed to be source files.
   Alternatively, you can specify one image file (.bin or .hex).
   The file extension for source and image files can be omitted,
   provided that only one file with a suitable extension exists.
   """ )
   
def Command_Line_List():
   return """
      #subheader -build
      Build the application, but do not download or debug it. 
      The default is to build and download (and maybe debug) 
      the application.

      #subheader -[no]catch
      Catch Python run-time errors that occur in mkt.py. 
      This is done by default.
      For debugging mkt.py it might be desirable to see 
      teh raw exception.
           
      #subheader -[no]cleanup
      The default is to empty the MicroKit temporary directory 
      before the build process starts. 
      This ensures that no files from a previous build are used.

      #subheader -[no]clever
      By default files specified on the command line can omit the 
      file extension, provided that only one file with a suitable extension
      is present. This cleverness can be disabled.

      #subheader -[no]config
      The applications configuration values can be show as 
      part of the build. The default is not to show this information.

      #subheader -docs
      The mkt.py file contains its own documentation. 
      This option creates the documentation files.
      
      #subheader -[no]echo
      This option shows the command lines of all external commands 
      (including all GNU tool invocations). The default is not
      to show this information.

      #subheader -[no]errorpause
      This option causes mkt to pause (wait for the user to press return)
      at the end when an error occurred.
      This can be usefull when mkt is run from in
      a subshell which is closed on termination.

      #subheader -[no]errors
      This option shows the list of unique (error) numbers that 
      have been assigned to appearances of #UNQIUE in the code.
      The default is not tos how this list.

      #subheader -[no]exceptions
      Include support for C++ exceptions. 
      This increases the code size considerably.
      The default is not to include exception support.      
      
      #subheader -go
      Run or debug the application, but doe not build it first.
      The default is to build the application and then run or debug it.
      
      #subheader -help
      Prints a summary of the command-line interface.
      
      #subheader -[no]kill
      Kill the debug backround programs (deamons) after a debugging session.
      The defalt is to do this.
      On XP this seems to take a lot of time, so it can be disabled.
      
      #subheader -[no]list
      Create listing files for all compiled sources, which show the
      generated assembler. These files are created in the mkt temporary 
      directory. This does not take much time, so
      it is enabled by default.
      
      #subheader -[no]optimize
      Instruct the compiler to optimize (for size). 
      The default is to do this.
      For debugging it might be wise to switch this off.
      
      #subheader -[no]pause
      This option causes mkt to pause (wait for the user to press return)
      at the end.
      This can be usefull when mkt is run from in
      a subshell which is closed on termination.
            
      #subheader -pspad
      Read the list of files that are part of the rpoject from
      the PsPad .ppr file.
      
      #subheader -pspadglue
      Write the glue files for PsPad which calls mkt using the -pspad option.
      
      #subheader -[no]python
      Make sure that compilation errors in the MicroKit-supplied 
      code refer to the appropriate line in the mkt.py file. 
      This takes considerable CPU time (and the MicroKit-supplied code 
      should never generate a compilation error), so the default is not
      to do this.
      
      #subheader -ram
      Build for, load into, and run from RAM. 
      The same effect can be achived by specifying memory=ram.
      
      #subheader -rom
      Build for, load into, and run from ROM (flash).
      The same effect can be achieved by specifying memory=rom.
      
      #subheader -run
      Just run an already built project.
      The default is to build and run.
            
      #subheader -[no]rtti
      By default no C++ Run Time Type Information is included, 
      because this increaes the code size considerably.
            
      #subheader -[no]sections
      By deafult mkt instructs the compiler and linker to place each global
      function and object in a separate section. 
      Hence functions and objects that are not used are eliminated.
      This reduces the code size, but it is not the standard way to use
      the GCC tools, so -nosections can be used to disable this
      feature.
      
      #subheader -[no]ignorepath
      : allow but ignore paths in source file names (default: no)
      
      #subheader -[no]size
      Show the sizes of all things in the application. 
      The dedfault is not to show these figures.
      
      #subheader -silent
      This option suppresses all mkt logging.
      The default is to log the building steps and neither print steps, nor echo tool commands
      
      #subheader -[no]term
      This option starts a serial terminal after downloading and starting teh application.
  
      #subheader -version
      With this option the mkt version is show.
  
      #subheader define syntax:
      item=value
   All other arguments (not starting with a -, do not contain a =)
   are assumed to be source files.
   Alternatively, you can specify one image file (.bin or .hex).
   The file extension for source and image files can be omitted,
   provided that only one file with a suitable extension exists.
      
   """   
   
class Switch:

   def __init__( self, Name, Default = 0 ):
      self.Name = Name.lower()
      self.Default = Default
      self.Val = Default
   
   def Parse( self, X ):
      if X == self.Name:
         self.Val = 1
         return 1
      if X == "no" + self.Name:
        self.Val = 0
        return 1
      return 0
   
   def Has( self, X ):
      return X == self.Name   
   
   def Value( self, Name ):
      return self.Val

   def __str__( self ):
      return "   %s = %s" % ( self.Name, self.Val )
   
class Build_Run_Go:

   def __init__( self ):
      self.Run = 1
      self.Build = 1
   
   def Parse( self, Option ):
      if Option == "go":
         self.Build = 1
         self.Run = 1
      elif Option == "build":
         self.Build = 1
         self.Run = 0
      elif Option == "run":
         self.Build = 0
         self.Run = 1
      elif Option == "norun":
         self.Run = 0
      elif Option == "nobuild":
         self.Build = 0
      else:
         return 0
      return 1
   
   def Has( self, Name ):
      return Name == "run" or Name == "build"  
   
   def Value( self, Name ):     
      if Name == "run":
         return self.Run
      if Name == "build":
         return self.Build   
      Errors.Panic( "Value requested for unknown build-run option [%s]" % Name )

   def __str__( self ):
      return "   Build = %d; Run = %d" % ( self.Build, self.Run )

class Specials():

   def Has( self, X ):
      return 0
     
   def Parse( self, X ):
      if X == "help":
         Print_Help()
         exit()
      if X == "pspadglue":
         PSPad_Glue()
         exit()
      return 0
    
   def __str__( self ):
      return "(specials)"
   
class Options_List:

   def __init__( self, List ):
      self.List = List
      self.Files = []
      self.Defines = []
      
   def Parse( self, X ):
      Y = X.lower()
      if Y == "-pspad":
         self.Files += Netbeans_Read()
      elif X == "-ram":
         Defines.append( "memory=ram" )
      elif X == "-rom":
         Defines.append( "memory=rom" )   
      elif Y[ 0 ] == "-":
         Y = Y[ 1 : ]
         for Option in self.List:
            if Option.Parse( Y ):
               return
         print( "\nunknown option [%s]" % Y )
         exit()
      elif X.find( "=" ) != -1:
         self.Defines.append( X )
      else:
         self.Files.append( X )
      
   def Value( self, Name ):
      for Option in self.List:
         if Option.Has( Name.lower()):
            return Option.Value( Name )
      Errors.Panic( "Value requested for unknown option [%s]" % Name )
    
   def __str__( self ):
      Result = ""
      for Option in self.List:
         Result += str( Option ) + "\n"
      # print "files=" + self.Files         
      return Result
         
def Run():        
   import traceback
   Options = Options_List([
      Build_Run_Go(),
      Specials(),
      Switch( "catch", 1 ),
      Switch( "cleanup", 1 ),
      Switch( "clever", 1 ),
      Switch( "config", 0 ),
      Switch( "docs", 0 ),
      Switch( "echo", 0 ),
      Switch( "exceptions", 0 ),
      Switch( "errorpause", 0 ),
      Switch( "errors", 0 ),
      Switch( "kill", 0 ),
      Switch( "list", 1 ),
      Switch( "optimize", 1 ),
      Switch( "pause", 0 ),
      Switch( "python", 0 ),
      Switch( "rtti", 0 ),
      Switch( "sections", 1 ),
      Switch( "size", 0 ),
      Switch( "silent", 0 ),
      Switch( "ignorepath", 0 ),
      Switch( "term", 0 ),
      Switch( "version", 0 ),
   ])
   if len( sys.argv ) < 2:
      print( "\n" )
      Print_Help()
   else:
      List = sys.argv[ 1 : ]
      while len( List ) > 0:
         Arg = List.pop(0) 
         Options.Parse( Arg )

      if not Options.Value( "silent" ):
         print( "%s %s (%s)" % ( Global.Name, Global.Version, Global.Modified ))

      Error = 1
      if not Options.Value( "version" ):
         try:
            Error = Project( Options ).Build()
         except Errors._Error:
            print( "Error: " + str( sys.exc_info()[ 1 ] ))
         except:
            if Options.Value( "catch" ):
               print( "uncaught exception:" )
               traceback.print_exc();     
      if( 
         Options.Value( "pause" )
         or ( Error and Options.Value( "errorpause" ))
      ):
         Global.Pause( "Press ENTER to exit" )
   
if __name__ == '__main__':
   Run()
   
   if 0:
      if len( sys.argv ) < 2:
         print( "usage: mkt_lib chip-name" )
         print( "chip-name can be:" )
         for Name in Chip_Names:
            print("    " + Name )
         print( "or 'all'" )
      else:
         Name = sys.argv[ 1 ].upper()
         if Name.lower() == "all":
            for Chip in Chip_Names:
               mkt_Chip_Lib( Chip )
         elif Name in Chip_Names:
            mkt_Chip_Lib( Name )
         else:
            print( "unknown chip '%s'" % sys.argv[ 1 ] )   
